This analysis is created for the Unstructured Text Analysis course at the Central European University. Special thanks to Eduardo Ariño de la Rubia who is the professor of this course as I learned a lot from him. This course is based on the wonderful book: Text-Mining-R-Tidy-Approach.

Technical introduction

The whole analysis is implemented in R and can be observed in this GitHub repository. The coding part can be separated into two main parts:

Throughout the whole process, I tried to follow the main principles of clean code, therefore one with R knowledge should follow it easily. There are plenty of further development possibilities in this project, therefore anyone who is interested, feel free to contact me David Utassy for any contribution. I will not show the whole code in this document, but I will highlight the most important snippets.

Introduction

By May 2021 the World and Hungary are hopefully getting out of the pandemic caused by the covid-19 virus. The most important tool we can use to defeat covid might be vaccines, therefore my aim was to analyze the communication of the Hungarian media in connection with vaccines. The main questions that this article tries to answer the following:

Data collection

Data collection in the project was a huge part, and we can also say that it is a never-ending story as we are talking about web scraping different news sites. I will not go into details, as it could be a standalone article. But, if someone is interested, the whole code can be found in the project’s GitHub repository.

On each and every news site, I went with the following steps:

Some summary statistics about the collected data:

Word frequency analysis

After good enough data collection and prepared I used the power of R and tidytext package to highlight the most used words by each news site. As a first step, I tokenized the articles by word and filtered out numbers. The second step was to remove stop words (frequently used but not really meaningful words). For that, a stop words dictionary is needed. As a first attempt, I used the out-of-the-box Hungarian stop-words from the tidytext package, however, according to my Hungarian domain knowledge it is missing some terms. On the other hand, the stop-words list from this GitHub repository worked very well, so I went on with this.

# unnest_tokens + remove numbers
tidy_all_sites <- all_sites %>% 
  unnest_tokens(word, content_full) %>% 
  filter(!str_detect(word, "\\d+"))

# removing stop words
hu_stop_word <- read_csv("https://raw.githubusercontent.com/stopwords-iso/stopwords-hu/master/stopwords-hu.txt", col_names = FALSE)
colnames(hu_stop_word) <- "word"

tidy_all_sites <- tidy_all_sites %>% anti_join(hu_stop_word)

After handling stopwords, we can instantly see the top 15 most frequently used words by each news site in the dataset. It is not a big surprise for the ones, who read the news these times, that in vaccine-related articles, the top words are like: “koronavirus” (covid-19), “egészségügyi” (healthcare system), “kormány” (government), “száma” (number), “fertőzöttek” (infectious), Pfizer, AstraZeneca, “kínai” (Chinese), “orosz” (Russian). Only by this basic plot, we can see, that the vaccine topic is highly related to (obviously) pandemic, politics and pharmaceutical companies.

frequent_words <- tidy_all_sites %>%
  group_by(site) %>% 
  count(word, sort = TRUE) %>%
  top_n(15) %>%
  mutate(word = reorder_within(word, n, site)) %>%
  ggplot(aes(word, n, fill=site)) + geom_col(show.legend = FALSE) + xlab(NULL) + ylab(NULL) +  coord_flip() +
  facet_wrap(~site, ncol=2, scales = "free") +
  scale_x_reordered()
frequent_words

According to the frequency of the words that are used by news sites, I calculated a correlation matrix and visualized it on a heatmap. From the heatmap below, we can see, that the correlation between the sites is between 0.3 and 0.4, however, within this range there are some differences. It can be observed, that 24.hu is the one that is mostly correlated with the other. The odd one-outs could be telex.hu and origo.hu. To explain this we can note that telex.hu just started working only in the third quarter of 2020, which might somewhat cause this, and origo.hu is the only site among these four that is known to be a pro-government news site.

frequency <- tidy_all_sites %>% 
  count(site, word) %>%
  group_by(site) %>%
  mutate(proportion = n / sum(n)) %>% 
  select(-n) %>% 
  spread(site, proportion)

colnames(frequency) <- c("word", "www.24.hu", "www.index.hu", "www.origo.hu", "www.telex.hu")

frequency <- frequency %>% mutate(www.origo.hu = coalesce(www.origo.hu,0),
                            www.telex.hu = coalesce(www.telex.hu,0),
                            www.index.hu = coalesce(www.index.hu,0),
                            www.24.hu = coalesce(www.24.hu,0))

# creating correlation matrix
ds_cor <- frequency %>%
  select(-word) %>% 
  as.matrix() %>%
  rcorr(type = "spearman")
correlation_matrix = as.data.frame(ds_cor$r)


matrix <- as.matrix(correlation_matrix)
diag(matrix) <- NA

heatmap<- ggplot(melt(matrix), aes(x = Var1, y = Var2, fill = value)) +
  geom_tile(colour = "white") +
  labs(x = 'Site', y = 'Site') +
  scale_fill_viridis(alpha = 0.7, begin = 1, end = 0.5, direction = 1, option = "A") +
  #theme_bg() +
  theme(legend.position = "right",
        legend.text = element_text(size=6),
        legend.title =element_text(size=6)
)

Also, let’s see another form of comparison between telex.hu and origo.hu according to the frequency of their words. We can see, that telex.hu is using the term vaccine more frequently. Also, I believe it is interesting to highlight, that the pro-governmental origo.hu using respectfully “Orbán Viktor” together, but telex.hu is just using “Orbán” as a standalone term.

telex_origo <- ggplot(frequency, aes(x = www.telex.hu, y = www.origo.hu, label = word)) + 
  geom_point(alpha=0.3) +
  geom_text(aes(label=word),hjust=0.5, vjust=-1, alpha=0.5) +
  geom_abline()
)

TF-IDF

To go deeper than just counting the most frequent words, I used the TF-IDF methodology. “TF-IDF is a statistical measure that evaluates how relevant a word is to a document in a collection of documents. This is done by multiplying two metrics: how many times a word appears in a document, and the inverse document frequency of the word across a set of documents.” (source).

During the process of calculating the TF-IDF metric, I observed the distribution of the term frequency by news site (plot below) on which we can see, that all of them follows a power-law distribution which can be used to validate, that the articles are written by human beings, and not generated by bots.

site_words <- all_sites %>% 
  unnest_tokens(word, content_full) %>% 
  count(site, word, sort = TRUE) %>% 
  ungroup()

total_words <- site_words %>% 
  group_by(site) %>% 
  summarise(total = sum(n))

site_words <- left_join(site_words, total_words)

term_freq <- ggplot(site_words, aes(n/total, fill=site)) +
  geom_histogram(show.legend = FALSE) +
  xlim(NA, 0.00015) +
  facet_wrap(~site, ncol=2, scales = "free_y")

In the following figure, we can see the most important words used by each news site according to the TF-IDF measure. This plot showed some interesting patterns. First of all, on the news site 24.hu more data cleaning is needed as there are some commercial words included. On the other hand, the pro-government news site has some highly political words like “Gyurcsányné” (the wife of a previous prime minister, and currently part of the Hungarian political opposition), “parkoló” (car parking slots in Budapest is a political hot topic).

freq_by_rank <- site_words %>% 
  group_by(site) %>% 
  mutate(rank = row_number(),
         term_freq = n/total)
  
site_words <- site_words %>% 
  bind_tf_idf(word, site, n)

tf_idf <- site_words %>% 
  arrange(desc(tf_idf)) %>% 
  mutate(word = factor(word, levels = rev(unique(word)))) %>% 
  group_by(site) %>% 
  top_n(10) %>% 
  ungroup() %>% 
  ggplot(aes(word, tf_idf, fill = site)) +
  geom_col(show.legend = F) +
  labs(x=NULL, y='tf-idf') +
  facet_wrap(~site, ncol=2, scales = "free") +
  coord_flip()

Ngram analysis

To dig even deeper, instead of tokenizing articles by word I used tidytext to tokenize by bigrams (word pairs).

bigrams_all_sites <- all_sites %>% unnest_tokens(bigram, content_full, token = "ngrams", n = 2) 

# getting hungarian stopwords
hu_stop_word <- read_csv("https://raw.githubusercontent.com/stopwords-iso/stopwords-hu/master/stopwords-hu.txt", col_names = FALSE)
colnames(hu_stop_word) <- "word"

# separating bigrams
bigrams_all_sites <- bigrams_all_sites %>% separate(bigram, c("word1", "word2"), sep = " ", remove  = F)

# filtering out bigrams containing stopwords
filtered_bigrams_all_sites <- bigrams_all_sites %>% 
  filter(!word1 %in% hu_stop_word$word) %>% 
  filter(!word2 %in% hu_stop_word$word)

# some basic summary
summary_bigrams_all_sites <- filtered_bigrams_all_sites %>% 
  count(word1, word2, sort = TRUE)

On the plot below, similarly to some previous ones, we can observe the most frequently used word pairs. This turned out to be a very powerful tool on my dataset as it showed some very interesting keywords (pairs). It is not really possible to make real differences between each site, therefore I would like to highlight some common patterns instead.

There are some obvious, pandemic related words:

Politicians:

Vaccine related keywords

bigram_freq <- filtered_bigrams_all_sites %>% 
  group_by(site) %>% 
  count(bigram, sort = TRUE) %>%
  top_n(10) %>%
  mutate(
    site = as.factor(site),
    bigram = reorder_within(bigram, n, site)) %>%
  ggplot(aes(bigram, n, fill=site)) + geom_col(show.legend = FALSE) + xlab(NULL) + coord_flip() +
  facet_wrap(~site, ncol=2, scales = "free") +
  scale_x_reordered()
bigram_freq

Sentiment analysis

Another level in analyzing unstructured text is to analyze the sentiment of it. The most interpretable way of doing it is to give a sentiment value to each and every word and aggregate these values into chosen units (sentences, paragraphs, articles). For this sentiment, a sentiment lexicon is needed. With English text, we have plenty of options, which is not the case with Hungarian text. One way could be to translate the whole data to English with some engine and make sentiment analysis on it in English. This is a way that is worth trying for sure, however, for this project, I went in another direction. Thanks to some wonderful people there is a Hungarian Sentiment Lexicon already out there in the public web that I used for my analysis. I followed Eduardo’s example to make use of this Sentiment lexicon.

positive_words <- read_csv("data/PrecoSenti/PrecoPos.txt", col_names = FALSE) %>%
  mutate(sentiment=1)
negative_words <- read_csv("data/PrecoSenti/PrecoNeg.txt", col_names = FALSE) %>%
  mutate(sentiment=-1)

hungarian_sentiment <- rbind(positive_words, negative_words)
colnames(hungarian_sentiment) <- c('word', 'sentiment')

tidy_all_sites_sentiment <- tidy_all_sites %>% inner_join(hungarian_sentiment)

In the following plot, I summarized the top words contributing to positive or negative sentiments on each news site. This figure makes sense as the most negative words were:

sentiment_contributions <- tidy_all_sites_sentiment %>%
  group_by(site) %>% 
  count(word, sentiment) %>% 
  mutate(word = reorder_within(word, abs(n), site)) %>%
  top_n(20) %>% 
  mutate(word = reorder_within(word, n, site)) %>%
  ggplot(aes(word, n * sentiment, fill = sentiment)) + geom_col(show.legend = FALSE) +
  labs(y = "Contribution to sentiment", x = NULL) + coord_flip() +
  facet_wrap(~site, ncol=2, scales = "free") +
  scale_x_reordered()

However, this also highlighted some interesting errors with this sentiment dictionary. It is not the fault of the dictionary as it is for general purposes. My finding was, that in covid context the word active has mostly negative sentiment opposite to the usual meaning due to “active covid cases”. Also the terms “negative” and “positive” have inverse sentiment in covid context (“positive test results”). By using bigrams I filtered for word pairs containing the terms above, and it turned out the for most of the cases, my assumption above was right, however not always, as they have been used with their usual meaning as well. As these words were in the top ones (contributing to sentiment results), I made the decision to exclude them from the sentiment dictionary for this time, to give them a neutral weight.

As all the articles were scraped with timestamp metadata, I was able to visualize the change of sentiment over time. As an exploratory data analysis, I did it with daily aggregation as well, but I found weekly aggregation more meaningful and less noisy. The figure below proves, that reading Hungarian covid-19 news, is somewhat depressing most of the time, as it shows the average sentiment of the observed news sites on a weekly basis.

weekly_sentiment_score <- tidy_all_sites_sentiment %>% 
  group_by(year = year(date),
           week = week(date)) %>% 
  summarise( daily_sentiment_norm = sum(sentiment)/n(),
             n=n(),
             daily_sentiment= sum(sentiment)) %>% 
  mutate( date = make_date(year) + weeks(week))

ggplot(weekly_sentiment_score, aes(x=date,y=daily_sentiment_norm)) +
  geom_col(show.legend = FALSE)

Furthermore, on the next plot we can observe similar plots grouped by news sites. We can see that indeed, telex.hu started only functioning in the 3rd quarter of 2020 with massively negative covid news. 24.hu seems to be kind of neutral compared to the others. Also, we can see some patterns as well but they are far from correlating with each other. This plot also highlights that there are probably some data quality or sentiment dictionary issues as there should not be such positive spikes.

weekly_sentiment_score <- tidy_all_sites_sentiment %>% 
  group_by(year = year(date),
           week = week(date),
           site) %>% 
  summarise( daily_sentiment_norm = sum(sentiment)/n(),
             n=n(),
             daily_sentiment= sum(sentiment)) %>% 
  mutate( date = make_date(year) + weeks(week))

ggplot(weekly_sentiment_score, aes(x=date,y=daily_sentiment_norm, fill = site)) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~site, ncol = 1, scales = "free_y")

Also, with the ngram analysis, we can analyse the contribution of words like “not” (in Hungarian: “nem”). With the following lines of code, I showed the top words that are followed “nem”(not) that had the largest impact on the sentiment. We can see, that most of these words have positive sentiment, meaning that the sentiment plots showed before should be even more negative in reality.

bigrams_all_sites %>% 
  filter(word1 == 'nem') %>% 
  count(bigram, sort = TRUE)

not_words <- bigrams_all_sites %>% 
  filter(word1 == 'nem') %>% 
  inner_join(hungarian_sentiment, by = c(word2 = 'word')) %>% 
  count(word2, sentiment, sort = TRUE) %>% 
  ungroup()

not_words_contribution <- not_words %>%  
  mutate(contribution = n * sentiment) %>% 
  arrange(desc(abs(contribution))) %>% 
  head(20) %>% 
  mutate(word2 = reorder(word2, contribution)) %>% 
  ggplot(aes(word2, contribution, fill = contribution > 0)) +
  geom_col(show.legend = F) +
  xlab('Word preceded by "nem" which is the hungarian form of "not".') +
  ylab('Sentiment score * number of occurences') +
  coord_flip()

Topic modelling: LDA

To cluster articles into some natural groups according to their content I tried a topic modeling method called LDA (Latent Dirichlet allocation). By that, we can treat each article as a mixture of topics.

On a basic level, we can do LDA easily with the help of the “topicmodels” package. With just a few lines of code, I managed to define 2 different topics with the following typical words. It is hard to differentiate the two topics (probably because the data collection is filtered on one keyword, and subtopic are highly connected to each other), but we could say, that topic 1 is more about “how the Hungarian government handles covid-19” and topic 2 is “healthcare system and vaccination”.

art_lda_2 <- LDA(word_all_sites_by_article_dtm, k = 2, control = list(seed = 1234))
art_topics_2 <- tidy(art_lda_2, matrix = "beta")

art_top_terms_2 <- art_topics_2 %>%
  group_by(topic) %>%
  top_n(10, beta) %>%
  ungroup() %>%
  arrange(topic, -beta)

art_topics_plot_2 <- art_top_terms_2 %>%
  mutate(term = reorder_within(term, beta, topic)) %>%
  ggplot(aes(term, beta, fill = factor(topic))) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ topic, scales = "free") +
  coord_flip() +
  scale_x_reordered()

Also with few lines of code, I clustered each article into one of the groups, and on a box plot, we can observe how the articles distributed between the topics within each news site. As I mentioned before, topic 1 is more about the Hungarian government and topic 2 about the healthcare system and vaccination. This aligns with the fact, that among the four new sites in the project origo.hu is the only pro-government news site as the pattern is different compared to the others.

gamma <- art_lda_2 %>%
  tidy(matrix = "gamma")

tmp <- left_join(gamma, all_sites, by = c("document" = "title"))

plot_2 <- tmp %>% 
  mutate(site = reorder(site, gamma * topic)) %>%
  ggplot(aes(factor(topic), gamma)) +
  geom_boxplot() +
  facet_wrap(~ site) +
  labs(x = "Topic",
       y = "# of messages where this was the highest % topic")

As we have four news sites it seemed to worth trying four different topics. I would label the following topics as the following according to my Hungarian knowledge.

  • Topic 1: Pandemic healthcare system
  • Topic 2: Vaccination
  • Topic 3: Hungarian government
  • Topic 4: Pandemic stats
art_lda_4 <- LDA(word_all_sites_by_article_dtm, k = 4, control = list(seed = 1234))
art_topics_4 <- tidy(art_lda_4, matrix = "beta")

art_top_terms_4 <- art_topics_4 %>%
  group_by(topic) %>%
  top_n(10, beta) %>%
  ungroup() %>%
  arrange(topic, -beta)

art_topics_plot_4 <- art_top_terms_4 %>%
  mutate(term = reorder_within(term, beta, topic)) %>%
  ggplot(aes(term, beta, fill = factor(topic))) +
  geom_col(show.legend = FALSE) +
  facet_wrap(~ topic, scales = "free") +
  coord_flip() +
  scale_x_reordered()

On the following familiar plot we can see, that regarding topic 1, most of the sites are doing similar. About topic 2 (vaccination) origo.hu is writing less than others. Also, with topic 3. (Hungarian Government) the odd-one-out is still orgio.hu. On topic four I would not highlight any meaningful pattern.

gamma <- art_lda_4 %>%
  tidy(matrix = "gamma")

tmp <- left_join(gamma, all_sites, by = c("document" = "title"))

plot_4 <- tmp %>% 
  mutate(site = reorder(site, gamma * topic)) %>%
  ggplot(aes(factor(topic), gamma)) +
  geom_boxplot() +
  facet_wrap(~ site) +
  labs(x = "Topic",
       y = "# of messages where this was the highest % topic")

Networks

To visualize the collected bigrams that were described in a previous chapter we can also use graphs using the ggraph package. First, let’s see a graph where nodes are words and they are connected with a weighted edge if they were used together a lot of times.

To highlight some distinct groups, on the left side we can see a group that is mostly about covid-statistics (number of infections). In the middle, there is a group talking about the Russian and the Chinese vaccine.

set.seed(2021)
network_all <- summary_bigrams_all_sites %>%
  filter(n >= 300) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
  geom_edge_link(aes(edge_alpha = 0.6, edge_width = n), edge_colour = "cyan4") +
  geom_node_point(size = 5) +
  geom_node_text(aes(label = name), repel = TRUE, 
                 point.padding = unit(0.2, "lines")) +
  theme_void()

On the other hand, with graph visualization, I think we can do better than just showing bigrams. With the “widyr” package, we can observe connections between words that appeared in the same article.

Again, with some lines of code here is the network of the most frequently co-occurred words in all the articles from all news sites. We can see that the main center point are “koronavírus” (covid-19), “vakcina” (vaccine), “járvány” (pandemic), “száma” (number of), and there are some separated but interesting groups like “Orbán Viktor” and “operatív törzs”(Hungarian organization that is handling the pandemic situation).

tidy_all_sites_by_article <- all_sites %>% 
  unnest_tokens(word, content_full) %>% 
  filter(!str_detect(word, "\\d+")) %>% 
  anti_join(hu_stop_word) %>% 
  count(title, word)

coocurring_words <- tidy_all_sites_by_article %>% pairwise_count(word, title, sort = TRUE, upper = FALSE)
saveRDS(coocurring_words, file = 'data/raw/coocurring_words_content.rds')


set.seed(1234)
coocurring_words_content_plot <- coocurring_words %>%
  filter(n >= 1050) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
  geom_edge_link(aes(edge_alpha = n, edge_width = n), edge_colour = "cyan4") +
  geom_node_point(size = 5) +
  geom_node_text(aes(label = name), repel = TRUE, 
                 point.padding = unit(0.2, "lines")) +
  theme_void()+
  ggtitle("Co-occuring words in the content of articles")

Also, with the same logic, I created the network of the co-occurring words in the title of articles, which shows an even more interesting pattern. It has three main groups:

# with content of titles
tidy_all_sites_by_title <- all_sites %>% 
  unnest_tokens(word, title, drop=F) %>% 
  filter(!str_detect(word, "\\d+")) %>% 
  anti_join(hu_stop_word) %>% 
  count(title, word)

coocurring_words_title <- tidy_all_sites_by_title %>% pairwise_count(word, title, sort = TRUE, upper = FALSE)
saveRDS(coocurring_words_title, file = 'data/raw/coocurring_words_title.rds')

set.seed(1234)

coocurring_words_content_plot_title <- coocurring_words_title %>%
  filter(n >= 15) %>%
  graph_from_data_frame() %>%
  ggraph(layout = "fr") +
  geom_edge_link(aes(edge_alpha = n, edge_width = n), edge_colour = "cyan4") +
  geom_node_point(size = 5) +
  geom_node_text(aes(label = name), repel = TRUE, 
                 point.padding = unit(0.2, "lines")) +
  theme_void()+
  ggtitle("Co-occuring words in all article titles")

Finally, let’s see the co-occurring words in the titles site by site. The interpretation of them is pretty straightforward by the nature of the graph visualization and we can say that the patterns are mostly the same at all news sites.

Conclusion

As a conclusion, I would like to highlight the power of R and the used packages in text mining and analysis. With the help of simple scripts, it is possible to get the main content out from thousands of articles and visualize them in an interpretable way. Also, I feel that this project could be an ongoing project as there are endless improvement possibilities in the following areas.

  • Scraping other news sites
  • More data cleaning for better quality
  • Trying to translate to English and use English dictionaries
  • Use covid related dictionaries
  • Deeper topic modeling
  • Deeper network analysis
LS0tCnRpdGxlOiAiSHVuZ2FyaWFuIG1lZGlhIGNvdmlkLTE5IHZhY2NpbmUgY29tbXVuaWNhdGlvbiIKYXV0aG9yOiAiRGF2aWQgVXRhc3N5IgpzdWJ0aXRsZTogIlVuc3RydWN0dXJlZCB0ZXh0IGFuYWx5c2lzIgpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIGRmX3ByaW50OiBwYWdlZAogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIGRmX3ByaW50OiBwYWdlZAotLS0KCgpUaGlzIGFuYWx5c2lzIGlzIGNyZWF0ZWQgZm9yIHRoZSBbVW5zdHJ1Y3R1cmVkIFRleHQgQW5hbHlzaXMgY291cnNlXShodHRwczovL2NvdXJzZXMuY2V1LmVkdS9jb3Vyc2VzLzIwMjAtMjAyMS9kYXRhLXNjaWVuY2UtMy11bnN0cnVjdHVyZWQtdGV4dC1hbmFseXNpcykgYXQgdGhlIENlbnRyYWwgRXVyb3BlYW4gVW5pdmVyc2l0eS4gIFNwZWNpYWwgdGhhbmtzIHRvIFtFZHVhcmRvIEFyacOxbyBkZSBsYSBSdWJpYV0oaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2luL2Vhcmluby8pIHdobyBpcyB0aGUgcHJvZmVzc29yIG9mIHRoaXMgY291cnNlIGFzIEkgbGVhcm5lZCBhIGxvdCBmcm9tIGhpbS4gVGhpcyBjb3Vyc2UgaXMgYmFzZWQgb24gdGhlIHdvbmRlcmZ1bCBib29rOiBbVGV4dC1NaW5pbmctUi1UaWR5LUFwcHJvYWNoXShodHRwczovL3d3dy5hbWF6b24uY29tL1RleHQtTWluaW5nLVItVGlkeS1BcHByb2FjaC9kcC8xNDkxOTgxNjUyL3JlZj1zcl8xXzE/aWU9VVRGOCZxaWQ9MTUxODg4MTYzOSZzcj04LTEma2V5d29yZHM9dGlkeXRleHQpLgoKIyMgVGVjaG5pY2FsIGludHJvZHVjdGlvbgoKVGhlIHdob2xlIGFuYWx5c2lzIGlzIGltcGxlbWVudGVkIGluIFIgYW5kIGNhbiBiZSBvYnNlcnZlZCBpbiBbdGhpcyBHaXRIdWIgcmVwb3NpdG9yeV0oaHR0cHM6Ly9naXRodWIuY29tL3V0YXNzeWR2L2h1bmdhcmlhbl92YWNjaW5lX21lZGlhX2NvbW11bmljYXRpb24pLiBUaGUgY29kaW5nIHBhcnQgY2FuIGJlIHNlcGFyYXRlZCBpbnRvIHR3byBtYWluIHBhcnRzOiAKCi0gV2ViIHNjcmFwaW5nIHBhcnRzCi0gVW5zdHJ1Y3R1cmVkIHRleHQgYW5hbHlzaXMgcGFydAoKVGhyb3VnaG91dCB0aGUgd2hvbGUgcHJvY2VzcywgSSB0cmllZCB0byBmb2xsb3cgdGhlIG1haW4gcHJpbmNpcGxlcyBvZiBjbGVhbiBjb2RlLCB0aGVyZWZvcmUgb25lIHdpdGggUiBrbm93bGVkZ2Ugc2hvdWxkIGZvbGxvdyBpdCBlYXNpbHkuIFRoZXJlIGFyZSBwbGVudHkgb2YgZnVydGhlciBkZXZlbG9wbWVudCBwb3NzaWJpbGl0aWVzIGluIHRoaXMgcHJvamVjdCwgdGhlcmVmb3JlIGFueW9uZSB3aG8gaXMgaW50ZXJlc3RlZCwgZmVlbCBmcmVlIHRvIGNvbnRhY3QgbWUgW0RhdmlkIFV0YXNzeV0oaHR0cHM6Ly93d3cubGlua2VkaW4uY29tL2luL2RhdmlkLXV0YXNzeS8pIGZvciBhbnkgY29udHJpYnV0aW9uLiBJIHdpbGwgbm90IHNob3cgdGhlIHdob2xlIGNvZGUgaW4gdGhpcyBkb2N1bWVudCwgYnV0IEkgd2lsbCBoaWdobGlnaHQgdGhlIG1vc3QgaW1wb3J0YW50IHNuaXBwZXRzLgoKIyMgSW50cm9kdWN0aW9uCgpCeSBNYXkgMjAyMSB0aGUgV29ybGQgYW5kIEh1bmdhcnkgYXJlIGhvcGVmdWxseSBnZXR0aW5nIG91dCBvZiB0aGUgcGFuZGVtaWMgY2F1c2VkIGJ5IHRoZSBjb3ZpZC0xOSB2aXJ1cy4gVGhlIG1vc3QgaW1wb3J0YW50IHRvb2wgd2UgY2FuIHVzZSB0byBkZWZlYXQgY292aWQgbWlnaHQgYmUgdmFjY2luZXMsIHRoZXJlZm9yZSBteSBhaW0gd2FzIHRvIGFuYWx5emUgdGhlIGNvbW11bmljYXRpb24gb2YgdGhlIEh1bmdhcmlhbiBtZWRpYSBpbiBjb25uZWN0aW9uIHdpdGggdmFjY2luZXMuIApUaGUgbWFpbiBxdWVzdGlvbnMgdGhhdCB0aGlzIGFydGljbGUgdHJpZXMgdG8gYW5zd2VyIHRoZSBmb2xsb3dpbmc6CgotIFdoYXQgYXJlIHRoZSBtYWluIHRvcGljcywgdGhhdCBhcmUgdXNlZCB3aXRoaW4gdGhlIHNhbWUgY29udGV4dCBhcyB2YWNjaW5lcz8KLSBIb3cgYXJlIGRpZmZlcmVudCBuZXdzIHNpdGXigJlzIGNvbW11bmljYXRpb24gY29tcGFyZWQgdG8gZWFjaCBvdGhlcj8KSXMgaXQgY2hhbmdpbmcgb3ZlciB0aW1lPwoKIyMgRGF0YSBjb2xsZWN0aW9uCgpEYXRhIGNvbGxlY3Rpb24gaW4gdGhlIHByb2plY3Qgd2FzIGEgaHVnZSBwYXJ0LCBhbmQgd2UgY2FuIGFsc28gc2F5IHRoYXQgaXQgaXMgYSBuZXZlci1lbmRpbmcgc3RvcnkgYXMgd2UgYXJlIHRhbGtpbmcgYWJvdXQgd2ViIHNjcmFwaW5nIGRpZmZlcmVudCBuZXdzIHNpdGVzLiBJIHdpbGwgbm90IGdvIGludG8gZGV0YWlscywgYXMgaXQgY291bGQgYmUgYSBzdGFuZGFsb25lIGFydGljbGUuIEJ1dCwgaWYgc29tZW9uZSBpcyBpbnRlcmVzdGVkLCB0aGUgd2hvbGUgY29kZSBjYW4gYmUgZm91bmQgW2luIHRoZSBwcm9qZWN04oCZcyBHaXRIdWIgcmVwb3NpdG9yeV0oaHR0cHM6Ly9naXRodWIuY29tL3V0YXNzeWR2L2h1bmdhcmlhbl92YWNjaW5lX21lZGlhX2NvbW11bmljYXRpb24pLgoKT24gZWFjaCBhbmQgZXZlcnkgbmV3cyBzaXRlLCBJIHdlbnQgd2l0aCB0aGUgZm9sbG93aW5nIHN0ZXBzOgoKLSBDb2xsZWN0IHRoZSBVUkwtcyBvZiBhbGwgdGhlIGFydGljbGVzIHRoYXQgY29udGFpbiB0aGUgd29yZCDigJx2YWtjaW5h4oCdIHdoaWNoIGlzIHRoZSBIdW5nYXJpYW4gZm9ybSBvZiB0aGUgdGVybSB2YWNjaW5lCi0gR2V0IGFsbCB0aGUgY29udGVudCBhbmQgbWV0YWRhdGEgZnJvbSBlYWNoIGFuZCBldmVyeSBhcnRpY2xlCi0gQ2xlYW4gdGhlIGNvbGxlY3RlZCBkYXRhCi0gU2F2ZSBpdCB0byBkaXNrCgpTb21lIHN1bW1hcnkgc3RhdGlzdGljcyBhYm91dCB0aGUgY29sbGVjdGVkIGRhdGE6CgotIFNjcmFwZWQgbmV3cyBzaXRlczogNCAoaW5kZXguaHUsIHRlbGV4Lmh1LCAyNC5odSwgb3JpZ28uaHUpCi0gU2NyYXBlZCBhcnRpY2xlczogMTAwMjgKLSBVc2VkIHRpbWVmcmFtZTogMjAyMC4wMS4wMSAtIFByZXNlbnQgKGNvdmlkLXRpbWUpCgojIyBXb3JkIGZyZXF1ZW5jeSBhbmFseXNpcwoKQWZ0ZXIgZ29vZCBlbm91Z2ggZGF0YSBjb2xsZWN0aW9uIGFuZCBwcmVwYXJlZCBJIHVzZWQgdGhlIHBvd2VyIG9mIFIgYW5kIHRpZHl0ZXh0IHBhY2thZ2UgdG8gaGlnaGxpZ2h0IHRoZSBtb3N0IHVzZWQgd29yZHMgYnkgZWFjaCBuZXdzIHNpdGUuIEFzIGEgZmlyc3Qgc3RlcCwgSSB0b2tlbml6ZWQgdGhlIGFydGljbGVzIGJ5IHdvcmQgYW5kIGZpbHRlcmVkIG91dCBudW1iZXJzLiBUaGUgc2Vjb25kIHN0ZXAgd2FzIHRvIHJlbW92ZSBzdG9wIHdvcmRzIChmcmVxdWVudGx5IHVzZWQgYnV0IG5vdCByZWFsbHkgbWVhbmluZ2Z1bCB3b3JkcykuIEZvciB0aGF0LCBhIHN0b3Agd29yZHMgZGljdGlvbmFyeSBpcyBuZWVkZWQuIEFzIGEgZmlyc3QgYXR0ZW1wdCwgSSB1c2VkIHRoZSBvdXQtb2YtdGhlLWJveCBIdW5nYXJpYW4gc3RvcC13b3JkcyBmcm9tIHRoZSB0aWR5dGV4dCBwYWNrYWdlLCBob3dldmVyLCBhY2NvcmRpbmcgdG8gbXkgSHVuZ2FyaWFuIGRvbWFpbiBrbm93bGVkZ2UgaXQgaXMgbWlzc2luZyBzb21lIHRlcm1zLiBPbiB0aGUgb3RoZXIgaGFuZCwgdGhlIHN0b3Atd29yZHMgbGlzdCBmcm9tIHRoaXMgW0dpdEh1YiByZXBvc2l0b3J5XShodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RvcHdvcmRzLWlzby9zdG9wd29yZHMtaHUvbWFzdGVyL3N0b3B3b3Jkcy1odS50eHQpIHdvcmtlZCB2ZXJ5IHdlbGwsIHNvIEkgd2VudCBvbiB3aXRoIHRoaXMuCgpgYGB7ciwgZXZhbD1GfQojIHVubmVzdF90b2tlbnMgKyByZW1vdmUgbnVtYmVycwp0aWR5X2FsbF9zaXRlcyA8LSBhbGxfc2l0ZXMgJT4lIAogIHVubmVzdF90b2tlbnMod29yZCwgY29udGVudF9mdWxsKSAlPiUgCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQsICJcXGQrIikpCgojIHJlbW92aW5nIHN0b3Agd29yZHMKaHVfc3RvcF93b3JkIDwtIHJlYWRfY3N2KCJodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vc3RvcHdvcmRzLWlzby9zdG9wd29yZHMtaHUvbWFzdGVyL3N0b3B3b3Jkcy1odS50eHQiLCBjb2xfbmFtZXMgPSBGQUxTRSkKY29sbmFtZXMoaHVfc3RvcF93b3JkKSA8LSAid29yZCIKCnRpZHlfYWxsX3NpdGVzIDwtIHRpZHlfYWxsX3NpdGVzICU+JSBhbnRpX2pvaW4oaHVfc3RvcF93b3JkKQpgYGAKCkFmdGVyIGhhbmRsaW5nIHN0b3B3b3Jkcywgd2UgY2FuIGluc3RhbnRseSBzZWUgdGhlIHRvcCAxNSBtb3N0IGZyZXF1ZW50bHkgdXNlZCB3b3JkcyBieSBlYWNoIG5ld3Mgc2l0ZSBpbiB0aGUgZGF0YXNldC4gSXQgaXMgbm90IGEgYmlnIHN1cnByaXNlIGZvciB0aGUgb25lcywgd2hvIHJlYWQgdGhlIG5ld3MgdGhlc2UgdGltZXMsIHRoYXQgaW4gdmFjY2luZS1yZWxhdGVkIGFydGljbGVzLCB0aGUgdG9wIHdvcmRzIGFyZSBsaWtlOiDigJxrb3JvbmF2aXJ1c+KAnSAoY292aWQtMTkpLCDigJxlZ8Opc3pzw6lnw7xneWnigJ0gKGhlYWx0aGNhcmUgc3lzdGVtKSwg4oCca29ybcOhbnnigJ0gKGdvdmVybm1lbnQpLCDigJxzesOhbWHigJ0gKG51bWJlciksIOKAnGZlcnTFkXrDtnR0ZWvigJ0gKGluZmVjdGlvdXMpLCBQZml6ZXIsIEFzdHJhWmVuZWNhLCDigJxrw61uYWnigJ0gKENoaW5lc2UpLCDigJxvcm9zeuKAnSAoUnVzc2lhbikuCk9ubHkgYnkgdGhpcyBiYXNpYyBwbG90LCB3ZSBjYW4gc2VlLCB0aGF0IHRoZSB2YWNjaW5lIHRvcGljIGlzIGhpZ2hseSByZWxhdGVkIHRvIChvYnZpb3VzbHkpIHBhbmRlbWljLCBwb2xpdGljcyBhbmQgcGhhcm1hY2V1dGljYWwgY29tcGFuaWVzLgoKYGBge3IsIGV2YWw9Rn0KZnJlcXVlbnRfd29yZHMgPC0gdGlkeV9hbGxfc2l0ZXMgJT4lCiAgZ3JvdXBfYnkoc2l0ZSkgJT4lIAogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUKICB0b3BfbigxNSkgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyX3dpdGhpbih3b3JkLCBuLCBzaXRlKSkgJT4lCiAgZ2dwbG90KGFlcyh3b3JkLCBuLCBmaWxsPXNpdGUpKSArIGdlb21fY29sKHNob3cubGVnZW5kID0gRkFMU0UpICsgeGxhYihOVUxMKSArIHlsYWIoTlVMTCkgKyAgY29vcmRfZmxpcCgpICsKICBmYWNldF93cmFwKH5zaXRlLCBuY29sPTIsIHNjYWxlcyA9ICJmcmVlIikgKwogIHNjYWxlX3hfcmVvcmRlcmVkKCkKZnJlcXVlbnRfd29yZHMKYGBgCgo8Y2VudGVyPiFbXSguLi9wbG90cy9mcmVxdWVudF93b3Jkcy5wbmcpe3dpZHRoPTkwJX08L2NlbnRlcj4gCgpBY2NvcmRpbmcgdG8gdGhlIGZyZXF1ZW5jeSBvZiB0aGUgd29yZHMgdGhhdCBhcmUgdXNlZCBieSBuZXdzIHNpdGVzLCBJIGNhbGN1bGF0ZWQgYSBjb3JyZWxhdGlvbiBtYXRyaXggYW5kIHZpc3VhbGl6ZWQgaXQgb24gYSBoZWF0bWFwLiBGcm9tIHRoZSBoZWF0bWFwIGJlbG93LCB3ZSBjYW4gc2VlLCB0aGF0IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIHRoZSBzaXRlcyBpcyBiZXR3ZWVuIDAuMyBhbmQgMC40LCBob3dldmVyLCB3aXRoaW4gdGhpcyByYW5nZSB0aGVyZSBhcmUgc29tZSBkaWZmZXJlbmNlcy4gSXQgY2FuIGJlIG9ic2VydmVkLCB0aGF0IDI0Lmh1IGlzIHRoZSBvbmUgdGhhdCBpcyBtb3N0bHkgY29ycmVsYXRlZCB3aXRoIHRoZSBvdGhlci4gVGhlIG9kZCBvbmUtb3V0cyBjb3VsZCBiZSB0ZWxleC5odSBhbmQgb3JpZ28uaHUuIFRvIGV4cGxhaW4gdGhpcyB3ZSBjYW4gbm90ZSB0aGF0IHRlbGV4Lmh1IGp1c3Qgc3RhcnRlZCB3b3JraW5nIG9ubHkgaW4gdGhlIHRoaXJkIHF1YXJ0ZXIgb2YgMjAyMCwgd2hpY2ggbWlnaHQgc29tZXdoYXQgY2F1c2UgdGhpcywgYW5kIG9yaWdvLmh1IGlzIHRoZSBvbmx5IHNpdGUgYW1vbmcgdGhlc2UgZm91ciB0aGF0IGlzIGtub3duIHRvIGJlIGEgcHJvLWdvdmVybm1lbnQgbmV3cyBzaXRlLiAKCmBgYHtyLCBldmFsPUZ9CmZyZXF1ZW5jeSA8LSB0aWR5X2FsbF9zaXRlcyAlPiUgCiAgY291bnQoc2l0ZSwgd29yZCkgJT4lCiAgZ3JvdXBfYnkoc2l0ZSkgJT4lCiAgbXV0YXRlKHByb3BvcnRpb24gPSBuIC8gc3VtKG4pKSAlPiUgCiAgc2VsZWN0KC1uKSAlPiUgCiAgc3ByZWFkKHNpdGUsIHByb3BvcnRpb24pCgpjb2xuYW1lcyhmcmVxdWVuY3kpIDwtIGMoIndvcmQiLCAid3d3LjI0Lmh1IiwgInd3dy5pbmRleC5odSIsICJ3d3cub3JpZ28uaHUiLCAid3d3LnRlbGV4Lmh1IikKCmZyZXF1ZW5jeSA8LSBmcmVxdWVuY3kgJT4lIG11dGF0ZSh3d3cub3JpZ28uaHUgPSBjb2FsZXNjZSh3d3cub3JpZ28uaHUsMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3d3cudGVsZXguaHUgPSBjb2FsZXNjZSh3d3cudGVsZXguaHUsMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3d3cuaW5kZXguaHUgPSBjb2FsZXNjZSh3d3cuaW5kZXguaHUsMCksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3d3cuMjQuaHUgPSBjb2FsZXNjZSh3d3cuMjQuaHUsMCkpCgojIGNyZWF0aW5nIGNvcnJlbGF0aW9uIG1hdHJpeApkc19jb3IgPC0gZnJlcXVlbmN5ICU+JQogIHNlbGVjdCgtd29yZCkgJT4lIAogIGFzLm1hdHJpeCgpICU+JQogIHJjb3JyKHR5cGUgPSAic3BlYXJtYW4iKQpjb3JyZWxhdGlvbl9tYXRyaXggPSBhcy5kYXRhLmZyYW1lKGRzX2NvciRyKQoKCm1hdHJpeCA8LSBhcy5tYXRyaXgoY29ycmVsYXRpb25fbWF0cml4KQpkaWFnKG1hdHJpeCkgPC0gTkEKCmhlYXRtYXA8LSBnZ3Bsb3QobWVsdChtYXRyaXgpLCBhZXMoeCA9IFZhcjEsIHkgPSBWYXIyLCBmaWxsID0gdmFsdWUpKSArCiAgZ2VvbV90aWxlKGNvbG91ciA9ICJ3aGl0ZSIpICsKICBsYWJzKHggPSAnU2l0ZScsIHkgPSAnU2l0ZScpICsKICBzY2FsZV9maWxsX3ZpcmlkaXMoYWxwaGEgPSAwLjcsIGJlZ2luID0gMSwgZW5kID0gMC41LCBkaXJlY3Rpb24gPSAxLCBvcHRpb24gPSAiQSIpICsKICAjdGhlbWVfYmcoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IiwKICAgICAgICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTYpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9ZWxlbWVudF90ZXh0KHNpemU9NikKKQpgYGAKCjxjZW50ZXI+IVtdKC4uL3Bsb3RzL2hlYXRtYXAucG5nKXt3aWR0aD05MCV9PC9jZW50ZXI+IAoKQWxzbywgbGV04oCZcyBzZWUgYW5vdGhlciBmb3JtIG9mIGNvbXBhcmlzb24gYmV0d2VlbiB0ZWxleC5odSBhbmQgb3JpZ28uaHUgYWNjb3JkaW5nIHRvIHRoZSBmcmVxdWVuY3kgb2YgdGhlaXIgd29yZHMuIFdlIGNhbiBzZWUsIHRoYXQgdGVsZXguaHUgaXMgdXNpbmcgdGhlIHRlcm0gdmFjY2luZSBtb3JlIGZyZXF1ZW50bHkuIEFsc28sIEkgYmVsaWV2ZSBpdCBpcyBpbnRlcmVzdGluZyB0byBoaWdobGlnaHQsIHRoYXQgdGhlIHByby1nb3Zlcm5tZW50YWwgb3JpZ28uaHUgdXNpbmcgcmVzcGVjdGZ1bGx5IOKAnE9yYsOhbiBWaWt0b3LigJ0gdG9nZXRoZXIsIGJ1dCB0ZWxleC5odSBpcyBqdXN0IHVzaW5nIOKAnE9yYsOhbuKAnSBhcyBhIHN0YW5kYWxvbmUgdGVybS4gCgpgYGB7ciwgZXZhbD1GfQp0ZWxleF9vcmlnbyA8LSBnZ3Bsb3QoZnJlcXVlbmN5LCBhZXMoeCA9IHd3dy50ZWxleC5odSwgeSA9IHd3dy5vcmlnby5odSwgbGFiZWwgPSB3b3JkKSkgKyAKICBnZW9tX3BvaW50KGFscGhhPTAuMykgKwogIGdlb21fdGV4dChhZXMobGFiZWw9d29yZCksaGp1c3Q9MC41LCB2anVzdD0tMSwgYWxwaGE9MC41KSArCiAgZ2VvbV9hYmxpbmUoKQopCmBgYAoKPGNlbnRlcj4hW10oLi4vcGxvdHMvY29tcGFyZV90ZWxleF9vcmlnby5wbmcpe3dpZHRoPTkwJX08L2NlbnRlcj4gCgojIyBURi1JREYKClRvIGdvIGRlZXBlciB0aGFuIGp1c3QgY291bnRpbmcgdGhlIG1vc3QgZnJlcXVlbnQgd29yZHMsIEkgdXNlZCB0aGUgVEYtSURGIG1ldGhvZG9sb2d5LgrigJxURi1JREYgaXMgYSBzdGF0aXN0aWNhbCBtZWFzdXJlIHRoYXQgZXZhbHVhdGVzIGhvdyByZWxldmFudCBhIHdvcmQgaXMgdG8gYSBkb2N1bWVudCBpbiBhIGNvbGxlY3Rpb24gb2YgZG9jdW1lbnRzLiBUaGlzIGlzIGRvbmUgYnkgbXVsdGlwbHlpbmcgdHdvIG1ldHJpY3M6IGhvdyBtYW55IHRpbWVzIGEgd29yZCBhcHBlYXJzIGluIGEgZG9jdW1lbnQsIGFuZCB0aGUgaW52ZXJzZSBkb2N1bWVudCBmcmVxdWVuY3kgb2YgdGhlIHdvcmQgYWNyb3NzIGEgc2V0IG9mIGRvY3VtZW50cy7igJ0gWyhzb3VyY2UpXShodHRwczovL21vbmtleWxlYXJuLmNvbS9ibG9nL3doYXQtaXMtdGYtaWRmLyM6fjp0ZXh0PVRGJTJESURGJTIwaXMlMjBhJTIwc3RhdGlzdGljYWwsYWNyb3NzJTIwYSUyMHNldCUyMG9mJTIwZG9jdW1lbnRzLikuCgpEdXJpbmcgdGhlIHByb2Nlc3Mgb2YgY2FsY3VsYXRpbmcgdGhlIFRGLUlERiBtZXRyaWMsIEkgb2JzZXJ2ZWQgdGhlIGRpc3RyaWJ1dGlvbiBvZiB0aGUgdGVybSBmcmVxdWVuY3kgYnkgbmV3cyBzaXRlIChwbG90IGJlbG93KSBvbiB3aGljaCB3ZSBjYW4gc2VlLCB0aGF0IGFsbCBvZiB0aGVtIGZvbGxvd3MgYSBwb3dlci1sYXcgZGlzdHJpYnV0aW9uIHdoaWNoIGNhbiBiZSB1c2VkIHRvIHZhbGlkYXRlLCB0aGF0IHRoZSBhcnRpY2xlcyBhcmUgd3JpdHRlbiBieSBodW1hbiBiZWluZ3MsIGFuZCBub3QgZ2VuZXJhdGVkIGJ5IGJvdHMuIAoKYGBge3IsIGV2YWw9Rn0Kc2l0ZV93b3JkcyA8LSBhbGxfc2l0ZXMgJT4lIAogIHVubmVzdF90b2tlbnMod29yZCwgY29udGVudF9mdWxsKSAlPiUgCiAgY291bnQoc2l0ZSwgd29yZCwgc29ydCA9IFRSVUUpICU+JSAKICB1bmdyb3VwKCkKCnRvdGFsX3dvcmRzIDwtIHNpdGVfd29yZHMgJT4lIAogIGdyb3VwX2J5KHNpdGUpICU+JSAKICBzdW1tYXJpc2UodG90YWwgPSBzdW0obikpCgpzaXRlX3dvcmRzIDwtIGxlZnRfam9pbihzaXRlX3dvcmRzLCB0b3RhbF93b3JkcykKCnRlcm1fZnJlcSA8LSBnZ3Bsb3Qoc2l0ZV93b3JkcywgYWVzKG4vdG90YWwsIGZpbGw9c2l0ZSkpICsKICBnZW9tX2hpc3RvZ3JhbShzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgeGxpbShOQSwgMC4wMDAxNSkgKwogIGZhY2V0X3dyYXAofnNpdGUsIG5jb2w9Miwgc2NhbGVzID0gImZyZWVfeSIpCmBgYAoKPGNlbnRlcj4hW10oLi4vcGxvdHMvdGVybV9mcmVxLnBuZyl7d2lkdGg9OTAlfTwvY2VudGVyPiAKCkluIHRoZSBmb2xsb3dpbmcgZmlndXJlLCB3ZSBjYW4gc2VlIHRoZSBtb3N0IGltcG9ydGFudCB3b3JkcyB1c2VkIGJ5IGVhY2ggbmV3cyBzaXRlIGFjY29yZGluZyB0byB0aGUgVEYtSURGIG1lYXN1cmUuIFRoaXMgcGxvdCBzaG93ZWQgc29tZSBpbnRlcmVzdGluZyBwYXR0ZXJucy4gRmlyc3Qgb2YgYWxsLCBvbiB0aGUgbmV3cyBzaXRlIDI0Lmh1IG1vcmUgZGF0YSBjbGVhbmluZyBpcyBuZWVkZWQgYXMgdGhlcmUgYXJlIHNvbWUgY29tbWVyY2lhbCB3b3JkcyBpbmNsdWRlZC4gT24gdGhlIG90aGVyIGhhbmQsIHRoZSBwcm8tZ292ZXJubWVudCBuZXdzIHNpdGUgaGFzIHNvbWUgaGlnaGx5IHBvbGl0aWNhbCB3b3JkcyBsaWtlIOKAnEd5dXJjc8Ohbnluw6nigJ0gKHRoZSB3aWZlIG9mIGEgcHJldmlvdXMgcHJpbWUgbWluaXN0ZXIsIGFuZCBjdXJyZW50bHkgcGFydCBvZiB0aGUgSHVuZ2FyaWFuIHBvbGl0aWNhbCBvcHBvc2l0aW9uKSwg4oCccGFya29sw7PigJ0gKGNhciBwYXJraW5nIHNsb3RzIGluIEJ1ZGFwZXN0IGlzIGEgcG9saXRpY2FsIGhvdCB0b3BpYykuCgpgYGB7ciwgZXZhbD1GfQpmcmVxX2J5X3JhbmsgPC0gc2l0ZV93b3JkcyAlPiUgCiAgZ3JvdXBfYnkoc2l0ZSkgJT4lIAogIG11dGF0ZShyYW5rID0gcm93X251bWJlcigpLAogICAgICAgICB0ZXJtX2ZyZXEgPSBuL3RvdGFsKQogIApzaXRlX3dvcmRzIDwtIHNpdGVfd29yZHMgJT4lIAogIGJpbmRfdGZfaWRmKHdvcmQsIHNpdGUsIG4pCgp0Zl9pZGYgPC0gc2l0ZV93b3JkcyAlPiUgCiAgYXJyYW5nZShkZXNjKHRmX2lkZikpICU+JSAKICBtdXRhdGUod29yZCA9IGZhY3Rvcih3b3JkLCBsZXZlbHMgPSByZXYodW5pcXVlKHdvcmQpKSkpICU+JSAKICBncm91cF9ieShzaXRlKSAlPiUgCiAgdG9wX24oMTApICU+JSAKICB1bmdyb3VwKCkgJT4lIAogIGdncGxvdChhZXMod29yZCwgdGZfaWRmLCBmaWxsID0gc2l0ZSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEYpICsKICBsYWJzKHg9TlVMTCwgeT0ndGYtaWRmJykgKwogIGZhY2V0X3dyYXAofnNpdGUsIG5jb2w9Miwgc2NhbGVzID0gImZyZWUiKSArCiAgY29vcmRfZmxpcCgpCmBgYAoKPGNlbnRlcj4hW10oLi4vcGxvdHMvdGZfaWRmLnBuZyl7d2lkdGg9OTAlfTwvY2VudGVyPiAKCiMjIE5ncmFtIGFuYWx5c2lzCgpUbyBkaWcgZXZlbiBkZWVwZXIsIGluc3RlYWQgb2YgdG9rZW5pemluZyBhcnRpY2xlcyBieSB3b3JkIEkgdXNlZCB0aWR5dGV4dCB0byB0b2tlbml6ZSBieSBiaWdyYW1zICh3b3JkIHBhaXJzKS4gCgpgYGB7ciwgZXZhbD1GfQpiaWdyYW1zX2FsbF9zaXRlcyA8LSBhbGxfc2l0ZXMgJT4lIHVubmVzdF90b2tlbnMoYmlncmFtLCBjb250ZW50X2Z1bGwsIHRva2VuID0gIm5ncmFtcyIsIG4gPSAyKSAKCiMgZ2V0dGluZyBodW5nYXJpYW4gc3RvcHdvcmRzCmh1X3N0b3Bfd29yZCA8LSByZWFkX2NzdigiaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3N0b3B3b3Jkcy1pc28vc3RvcHdvcmRzLWh1L21hc3Rlci9zdG9wd29yZHMtaHUudHh0IiwgY29sX25hbWVzID0gRkFMU0UpCmNvbG5hbWVzKGh1X3N0b3Bfd29yZCkgPC0gIndvcmQiCgojIHNlcGFyYXRpbmcgYmlncmFtcwpiaWdyYW1zX2FsbF9zaXRlcyA8LSBiaWdyYW1zX2FsbF9zaXRlcyAlPiUgc2VwYXJhdGUoYmlncmFtLCBjKCJ3b3JkMSIsICJ3b3JkMiIpLCBzZXAgPSAiICIsIHJlbW92ZSAgPSBGKQoKIyBmaWx0ZXJpbmcgb3V0IGJpZ3JhbXMgY29udGFpbmluZyBzdG9wd29yZHMKZmlsdGVyZWRfYmlncmFtc19hbGxfc2l0ZXMgPC0gYmlncmFtc19hbGxfc2l0ZXMgJT4lIAogIGZpbHRlcighd29yZDEgJWluJSBodV9zdG9wX3dvcmQkd29yZCkgJT4lIAogIGZpbHRlcighd29yZDIgJWluJSBodV9zdG9wX3dvcmQkd29yZCkKCiMgc29tZSBiYXNpYyBzdW1tYXJ5CnN1bW1hcnlfYmlncmFtc19hbGxfc2l0ZXMgPC0gZmlsdGVyZWRfYmlncmFtc19hbGxfc2l0ZXMgJT4lIAogIGNvdW50KHdvcmQxLCB3b3JkMiwgc29ydCA9IFRSVUUpCmBgYAoKT24gdGhlIHBsb3QgYmVsb3csIHNpbWlsYXJseSB0byBzb21lIHByZXZpb3VzIG9uZXMsIHdlIGNhbiBvYnNlcnZlIHRoZSBtb3N0IGZyZXF1ZW50bHkgdXNlZCB3b3JkIHBhaXJzLiBUaGlzIHR1cm5lZCBvdXQgdG8gYmUgYSB2ZXJ5IHBvd2VyZnVsIHRvb2wgb24gbXkgZGF0YXNldCBhcyBpdCBzaG93ZWQgc29tZSB2ZXJ5IGludGVyZXN0aW5nIGtleXdvcmRzIChwYWlycykuIEl0IGlzIG5vdCByZWFsbHkgcG9zc2libGUgdG8gbWFrZSByZWFsIGRpZmZlcmVuY2VzIGJldHdlZW4gZWFjaCBzaXRlLCB0aGVyZWZvcmUgSSB3b3VsZCBsaWtlIHRvIGhpZ2hsaWdodCBzb21lIGNvbW1vbiBwYXR0ZXJucyBpbnN0ZWFkLgoKVGhlcmUgYXJlIHNvbWUgb2J2aW91cywgcGFuZGVtaWMgcmVsYXRlZCB3b3JkczoKCi0gY292aWQgMTkKLSBmZXJ0xZF6w7Z0dGVrIHN6w6FtYSAobnVtYmVyIG9mIGluZmVjdGVkIHBlb3BsZSkKLSBNw7xsbGVyIENlY8OtbGlhIChzaGUgaXMgdGhlIENoaWVmIE1lZGljYWwgT2ZmaWNlciBvZiBIdW5nYXJ5KQotIE9yc3rDoWdvcyB0aXN6dGlmxZFvcnZvcnMgKENoaWVmIE1lZGljYWwgT2ZmaWNlciBvZiBIdW5nYXJ5KQotIE1pbGxpw7MgYWRhZyAobWlsbGlvbiBwcm9wb3J0aW9ucykKClBvbGl0aWNpYW5zOgoKLSBPcmLDoW4gVmlrdG9yCi0gR3VsecOhcyBHZXJnZWx5CgpWYWNjaW5lIHJlbGF0ZWQga2V5d29yZHMKCi0gUGZpemVyIGJpb250ZWNoCi0gU3pwdXRueWlrIFYKCmBgYHtyLCBldmFsPUZ9CmJpZ3JhbV9mcmVxIDwtIGZpbHRlcmVkX2JpZ3JhbXNfYWxsX3NpdGVzICU+JSAKICBncm91cF9ieShzaXRlKSAlPiUgCiAgY291bnQoYmlncmFtLCBzb3J0ID0gVFJVRSkgJT4lCiAgdG9wX24oMTApICU+JQogIG11dGF0ZSgKICAgIHNpdGUgPSBhcy5mYWN0b3Ioc2l0ZSksCiAgICBiaWdyYW0gPSByZW9yZGVyX3dpdGhpbihiaWdyYW0sIG4sIHNpdGUpKSAlPiUKICBnZ3Bsb3QoYWVzKGJpZ3JhbSwgbiwgZmlsbD1zaXRlKSkgKyBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArIHhsYWIoTlVMTCkgKyBjb29yZF9mbGlwKCkgKwogIGZhY2V0X3dyYXAofnNpdGUsIG5jb2w9Miwgc2NhbGVzID0gImZyZWUiKSArCiAgc2NhbGVfeF9yZW9yZGVyZWQoKQpiaWdyYW1fZnJlcQpgYGAKCjxjZW50ZXI+IVtdKC4uL3Bsb3RzL2JpZ3JhbV9mcmVxLnBuZyl7d2lkdGg9OTAlfTwvY2VudGVyPiAKCiMgU2VudGltZW50IGFuYWx5c2lzCgpBbm90aGVyIGxldmVsIGluIGFuYWx5emluZyB1bnN0cnVjdHVyZWQgdGV4dCBpcyB0byBhbmFseXplIHRoZSBzZW50aW1lbnQgb2YgaXQuIFRoZSBtb3N0IGludGVycHJldGFibGUgd2F5IG9mIGRvaW5nIGl0IGlzIHRvIGdpdmUgYSBzZW50aW1lbnQgdmFsdWUgdG8gZWFjaCBhbmQgZXZlcnkgd29yZCBhbmQgYWdncmVnYXRlIHRoZXNlIHZhbHVlcyBpbnRvIGNob3NlbiB1bml0cyAoc2VudGVuY2VzLCBwYXJhZ3JhcGhzLCBhcnRpY2xlcykuIEZvciB0aGlzIHNlbnRpbWVudCwgYSBzZW50aW1lbnQgbGV4aWNvbiBpcyBuZWVkZWQuIFdpdGggRW5nbGlzaCB0ZXh0LCB3ZSBoYXZlIHBsZW50eSBvZiBvcHRpb25zLCB3aGljaCBpcyBub3QgdGhlIGNhc2Ugd2l0aCBIdW5nYXJpYW4gdGV4dC4gT25lIHdheSBjb3VsZCBiZSB0byB0cmFuc2xhdGUgdGhlIHdob2xlIGRhdGEgdG8gRW5nbGlzaCB3aXRoIHNvbWUgZW5naW5lIGFuZCBtYWtlIHNlbnRpbWVudCBhbmFseXNpcyBvbiBpdCBpbiBFbmdsaXNoLiBUaGlzIGlzIGEgd2F5IHRoYXQgaXMgd29ydGggdHJ5aW5nIGZvciBzdXJlLCBob3dldmVyLCBmb3IgdGhpcyBwcm9qZWN0LCBJIHdlbnQgaW4gYW5vdGhlciBkaXJlY3Rpb24uIApUaGFua3MgdG8gc29tZSB3b25kZXJmdWwgcGVvcGxlIHRoZXJlIGlzIGEgW0h1bmdhcmlhbiBTZW50aW1lbnQgTGV4aWNvbl0oaHR0cDovL29wZW5kYXRhLmh1L2h1L2RhdGFzZXQvaHVuZ2FyaWFuLXNlbnRpbWVudC1sZXhpY29uKSBhbHJlYWR5IG91dCB0aGVyZSBpbiB0aGUgcHVibGljIHdlYiB0aGF0IEkgdXNlZCBmb3IgbXkgYW5hbHlzaXMuIEkgZm9sbG93ZWQgRWR1YXJkb+KAmXMgW2V4YW1wbGVdKGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL2Vhcmluby8yNDYyNTZjOTE2MWRhMTE3NzAxZGQwMTY1ZWIwMmU2MSkgdG8gbWFrZSB1c2Ugb2YgdGhpcyBTZW50aW1lbnQgbGV4aWNvbi4gCgpgYGB7ciwgZXZhbD1GfQpwb3NpdGl2ZV93b3JkcyA8LSByZWFkX2NzdigiZGF0YS9QcmVjb1NlbnRpL1ByZWNvUG9zLnR4dCIsIGNvbF9uYW1lcyA9IEZBTFNFKSAlPiUKICBtdXRhdGUoc2VudGltZW50PTEpCm5lZ2F0aXZlX3dvcmRzIDwtIHJlYWRfY3N2KCJkYXRhL1ByZWNvU2VudGkvUHJlY29OZWcudHh0IiwgY29sX25hbWVzID0gRkFMU0UpICU+JQogIG11dGF0ZShzZW50aW1lbnQ9LTEpCgpodW5nYXJpYW5fc2VudGltZW50IDwtIHJiaW5kKHBvc2l0aXZlX3dvcmRzLCBuZWdhdGl2ZV93b3JkcykKY29sbmFtZXMoaHVuZ2FyaWFuX3NlbnRpbWVudCkgPC0gYygnd29yZCcsICdzZW50aW1lbnQnKQoKdGlkeV9hbGxfc2l0ZXNfc2VudGltZW50IDwtIHRpZHlfYWxsX3NpdGVzICU+JSBpbm5lcl9qb2luKGh1bmdhcmlhbl9zZW50aW1lbnQpCmBgYAoKSW4gdGhlIGZvbGxvd2luZyBwbG90LCBJIHN1bW1hcml6ZWQgdGhlIHRvcCB3b3JkcyBjb250cmlidXRpbmcgdG8gcG9zaXRpdmUgb3IgbmVnYXRpdmUgc2VudGltZW50cyBvbiBlYWNoIG5ld3Mgc2l0ZS4gVGhpcyBmaWd1cmUgbWFrZXMgc2Vuc2UgYXMgdGhlIG1vc3QgbmVnYXRpdmUgd29yZHMgd2VyZToKCi0gasOhcnbDoW55IChwYW5kZW1pYykKLSB2w61ydXMgKHZpcnVzKQotIGtyw7NuaWt1cyAoY2hyb25pYykKLSBiZXRlZyAocGF0aWVudCkKLSBoYWzDoWxvcyAoZGVhZGx5KQotIGZlcnrFkXrDqXMgKGluZmVjdGlvbikKCmBgYHtyLCBldmFsPUZ9CnNlbnRpbWVudF9jb250cmlidXRpb25zIDwtIHRpZHlfYWxsX3NpdGVzX3NlbnRpbWVudCAlPiUKICBncm91cF9ieShzaXRlKSAlPiUgCiAgY291bnQod29yZCwgc2VudGltZW50KSAlPiUgCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyX3dpdGhpbih3b3JkLCBhYnMobiksIHNpdGUpKSAlPiUKICB0b3BfbigyMCkgJT4lIAogIG11dGF0ZSh3b3JkID0gcmVvcmRlcl93aXRoaW4od29yZCwgbiwgc2l0ZSkpICU+JQogIGdncGxvdChhZXMod29yZCwgbiAqIHNlbnRpbWVudCwgZmlsbCA9IHNlbnRpbWVudCkpICsgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkgKwogIGxhYnMoeSA9ICJDb250cmlidXRpb24gdG8gc2VudGltZW50IiwgeCA9IE5VTEwpICsgY29vcmRfZmxpcCgpICsKICBmYWNldF93cmFwKH5zaXRlLCBuY29sPTIsIHNjYWxlcyA9ICJmcmVlIikgKwogIHNjYWxlX3hfcmVvcmRlcmVkKCkKYGBgCgo8Y2VudGVyPiFbXSguLi9wbG90cy9zZW50aW1lbnRfY29udHJpYnV0aW9ucy5wbmcpe3dpZHRoPTkwJX08L2NlbnRlcj4gCgpIb3dldmVyLCB0aGlzIGFsc28gaGlnaGxpZ2h0ZWQgc29tZSBpbnRlcmVzdGluZyBlcnJvcnMgd2l0aCB0aGlzIHNlbnRpbWVudCBkaWN0aW9uYXJ5LiBJdCBpcyBub3QgdGhlIGZhdWx0IG9mIHRoZSBkaWN0aW9uYXJ5IGFzIGl0IGlzIGZvciBnZW5lcmFsIHB1cnBvc2VzLiBNeSBmaW5kaW5nIHdhcywgdGhhdCBpbiBjb3ZpZCBjb250ZXh0IHRoZSB3b3JkIGFjdGl2ZSBoYXMgbW9zdGx5IG5lZ2F0aXZlIHNlbnRpbWVudCBvcHBvc2l0ZSB0byB0aGUgdXN1YWwgbWVhbmluZyBkdWUgdG8g4oCcYWN0aXZlIGNvdmlkIGNhc2Vz4oCdLiBBbHNvIHRoZSB0ZXJtcyDigJxuZWdhdGl2ZeKAnSBhbmQg4oCccG9zaXRpdmXigJ0gaGF2ZSBpbnZlcnNlIHNlbnRpbWVudCBpbiBjb3ZpZCBjb250ZXh0ICjigJxwb3NpdGl2ZSB0ZXN0IHJlc3VsdHPigJ0pLiBCeSB1c2luZyBiaWdyYW1zIEkgZmlsdGVyZWQgZm9yIHdvcmQgcGFpcnMgY29udGFpbmluZyB0aGUgdGVybXMgYWJvdmUsIGFuZCBpdCB0dXJuZWQgb3V0IHRoZSBmb3IgbW9zdCBvZiB0aGUgY2FzZXMsIG15IGFzc3VtcHRpb24gYWJvdmUgd2FzIHJpZ2h0LCBob3dldmVyIG5vdCBhbHdheXMsIGFzIHRoZXkgaGF2ZSBiZWVuIHVzZWQgd2l0aCB0aGVpciB1c3VhbCBtZWFuaW5nIGFzIHdlbGwuIEFzIHRoZXNlIHdvcmRzIHdlcmUgaW4gdGhlIHRvcCBvbmVzIChjb250cmlidXRpbmcgdG8gc2VudGltZW50IHJlc3VsdHMpLCBJIG1hZGUgdGhlIGRlY2lzaW9uIHRvIGV4Y2x1ZGUgdGhlbSBmcm9tIHRoZSBzZW50aW1lbnQgZGljdGlvbmFyeSBmb3IgdGhpcyB0aW1lLCB0byBnaXZlIHRoZW0gYSBuZXV0cmFsIHdlaWdodC4gCgpBcyBhbGwgdGhlIGFydGljbGVzIHdlcmUgc2NyYXBlZCB3aXRoIHRpbWVzdGFtcCBtZXRhZGF0YSwgSSB3YXMgYWJsZSB0byB2aXN1YWxpemUgdGhlIGNoYW5nZSBvZiBzZW50aW1lbnQgb3ZlciB0aW1lLiBBcyBhbiBleHBsb3JhdG9yeSBkYXRhIGFuYWx5c2lzLCBJIGRpZCBpdCB3aXRoIGRhaWx5IGFnZ3JlZ2F0aW9uIGFzIHdlbGwsIGJ1dCBJIGZvdW5kIHdlZWtseSBhZ2dyZWdhdGlvbiBtb3JlIG1lYW5pbmdmdWwgYW5kIGxlc3Mgbm9pc3kuIFRoZSBmaWd1cmUgYmVsb3cgcHJvdmVzLCB0aGF0IHJlYWRpbmcgSHVuZ2FyaWFuIGNvdmlkLTE5IG5ld3MsIGlzIHNvbWV3aGF0IGRlcHJlc3NpbmcgbW9zdCBvZiB0aGUgdGltZSwgYXMgaXQgc2hvd3MgdGhlIGF2ZXJhZ2Ugc2VudGltZW50IG9mIHRoZSBvYnNlcnZlZCBuZXdzIHNpdGVzIG9uIGEgd2Vla2x5IGJhc2lzLiAKCmBgYHtyLCBldmFsPUZ9CndlZWtseV9zZW50aW1lbnRfc2NvcmUgPC0gdGlkeV9hbGxfc2l0ZXNfc2VudGltZW50ICU+JSAKICBncm91cF9ieSh5ZWFyID0geWVhcihkYXRlKSwKICAgICAgICAgICB3ZWVrID0gd2VlayhkYXRlKSkgJT4lIAogIHN1bW1hcmlzZSggZGFpbHlfc2VudGltZW50X25vcm0gPSBzdW0oc2VudGltZW50KS9uKCksCiAgICAgICAgICAgICBuPW4oKSwKICAgICAgICAgICAgIGRhaWx5X3NlbnRpbWVudD0gc3VtKHNlbnRpbWVudCkpICU+JSAKICBtdXRhdGUoIGRhdGUgPSBtYWtlX2RhdGUoeWVhcikgKyB3ZWVrcyh3ZWVrKSkKCmdncGxvdCh3ZWVrbHlfc2VudGltZW50X3Njb3JlLCBhZXMoeD1kYXRlLHk9ZGFpbHlfc2VudGltZW50X25vcm0pKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGQUxTRSkKYGBgCgo8Y2VudGVyPiFbXSguLi9wbG90cy93ZWVrbHlfYWdfc2VudGltZW50LnBuZyl7d2lkdGg9OTAlfTwvY2VudGVyPiAKCkZ1cnRoZXJtb3JlLCBvbiB0aGUgbmV4dCBwbG90IHdlIGNhbiBvYnNlcnZlIHNpbWlsYXIgcGxvdHMgZ3JvdXBlZCBieSBuZXdzIHNpdGVzLiBXZSBjYW4gc2VlIHRoYXQgaW5kZWVkLCB0ZWxleC5odSBzdGFydGVkIG9ubHkgZnVuY3Rpb25pbmcgaW4gdGhlIDNyZCBxdWFydGVyIG9mIDIwMjAgd2l0aCBtYXNzaXZlbHkgbmVnYXRpdmUgY292aWQgbmV3cy4gMjQuaHUgc2VlbXMgdG8gYmUga2luZCBvZiBuZXV0cmFsIGNvbXBhcmVkIHRvIHRoZSBvdGhlcnMuIEFsc28sIHdlIGNhbiBzZWUgc29tZSBwYXR0ZXJucyBhcyB3ZWxsIGJ1dCB0aGV5IGFyZSBmYXIgZnJvbSBjb3JyZWxhdGluZyB3aXRoIGVhY2ggb3RoZXIuIFRoaXMgcGxvdCBhbHNvIGhpZ2hsaWdodHMgdGhhdCB0aGVyZSBhcmUgcHJvYmFibHkgc29tZSBkYXRhIHF1YWxpdHkgb3Igc2VudGltZW50IGRpY3Rpb25hcnkgaXNzdWVzIGFzIHRoZXJlIHNob3VsZCBub3QgYmUgc3VjaCBwb3NpdGl2ZSBzcGlrZXMuIAoKYGBge3IsIGV2YWw9Rn0Kd2Vla2x5X3NlbnRpbWVudF9zY29yZSA8LSB0aWR5X2FsbF9zaXRlc19zZW50aW1lbnQgJT4lIAogIGdyb3VwX2J5KHllYXIgPSB5ZWFyKGRhdGUpLAogICAgICAgICAgIHdlZWsgPSB3ZWVrKGRhdGUpLAogICAgICAgICAgIHNpdGUpICU+JSAKICBzdW1tYXJpc2UoIGRhaWx5X3NlbnRpbWVudF9ub3JtID0gc3VtKHNlbnRpbWVudCkvbigpLAogICAgICAgICAgICAgbj1uKCksCiAgICAgICAgICAgICBkYWlseV9zZW50aW1lbnQ9IHN1bShzZW50aW1lbnQpKSAlPiUgCiAgbXV0YXRlKCBkYXRlID0gbWFrZV9kYXRlKHllYXIpICsgd2Vla3Mod2VlaykpCgpnZ3Bsb3Qod2Vla2x5X3NlbnRpbWVudF9zY29yZSwgYWVzKHg9ZGF0ZSx5PWRhaWx5X3NlbnRpbWVudF9ub3JtLCBmaWxsID0gc2l0ZSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+c2l0ZSwgbmNvbCA9IDEsIHNjYWxlcyA9ICJmcmVlX3kiKQpgYGAKCjxjZW50ZXI+IVtdKC4uL3Bsb3RzL3dlZWtseV9zaXRlX3NlbnRpbWVudC5wbmcpe3dpZHRoPTkwJX08L2NlbnRlcj4KCkFsc28sIHdpdGggdGhlIG5ncmFtIGFuYWx5c2lzLCB3ZSBjYW4gYW5hbHlzZSB0aGUgY29udHJpYnV0aW9uIG9mIHdvcmRzIGxpa2Ug4oCcbm904oCdIChpbiBIdW5nYXJpYW46IOKAnG5lbeKAnSkuICBXaXRoIHRoZSBmb2xsb3dpbmcgbGluZXMgb2YgY29kZSwgSSBzaG93ZWQgdGhlIHRvcCB3b3JkcyB0aGF0IGFyZSBmb2xsb3dlZCDigJxuZW3igJ0obm90KSB0aGF0IGhhZCB0aGUgbGFyZ2VzdCBpbXBhY3Qgb24gdGhlIHNlbnRpbWVudC4gV2UgY2FuIHNlZSwgdGhhdCBtb3N0IG9mIHRoZXNlIHdvcmRzIGhhdmUgcG9zaXRpdmUgc2VudGltZW50LCBtZWFuaW5nIHRoYXQgdGhlIHNlbnRpbWVudCBwbG90cyBzaG93ZWQgYmVmb3JlIHNob3VsZCBiZSBldmVuIG1vcmUgbmVnYXRpdmUgaW4gcmVhbGl0eS4KCmBgYHtyLCBldmFsPUZ9CmJpZ3JhbXNfYWxsX3NpdGVzICU+JSAKICBmaWx0ZXIod29yZDEgPT0gJ25lbScpICU+JSAKICBjb3VudChiaWdyYW0sIHNvcnQgPSBUUlVFKQoKbm90X3dvcmRzIDwtIGJpZ3JhbXNfYWxsX3NpdGVzICU+JSAKICBmaWx0ZXIod29yZDEgPT0gJ25lbScpICU+JSAKICBpbm5lcl9qb2luKGh1bmdhcmlhbl9zZW50aW1lbnQsIGJ5ID0gYyh3b3JkMiA9ICd3b3JkJykpICU+JSAKICBjb3VudCh3b3JkMiwgc2VudGltZW50LCBzb3J0ID0gVFJVRSkgJT4lIAogIHVuZ3JvdXAoKQoKbm90X3dvcmRzX2NvbnRyaWJ1dGlvbiA8LSBub3Rfd29yZHMgJT4lICAKICBtdXRhdGUoY29udHJpYnV0aW9uID0gbiAqIHNlbnRpbWVudCkgJT4lIAogIGFycmFuZ2UoZGVzYyhhYnMoY29udHJpYnV0aW9uKSkpICU+JSAKICBoZWFkKDIwKSAlPiUgCiAgbXV0YXRlKHdvcmQyID0gcmVvcmRlcih3b3JkMiwgY29udHJpYnV0aW9uKSkgJT4lIAogIGdncGxvdChhZXMod29yZDIsIGNvbnRyaWJ1dGlvbiwgZmlsbCA9IGNvbnRyaWJ1dGlvbiA+IDApKSArCiAgZ2VvbV9jb2woc2hvdy5sZWdlbmQgPSBGKSArCiAgeGxhYignV29yZCBwcmVjZWRlZCBieSAibmVtIiB3aGljaCBpcyB0aGUgaHVuZ2FyaWFuIGZvcm0gb2YgIm5vdCIuJykgKwogIHlsYWIoJ1NlbnRpbWVudCBzY29yZSAqIG51bWJlciBvZiBvY2N1cmVuY2VzJykgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCjxjZW50ZXI+IVtdKC4uL3Bsb3RzL25vdF93b3Jkc19jb250cmlidXRpb24ucG5nKXt3aWR0aD05MCV9PC9jZW50ZXI+CgojIyBUb3BpYyBtb2RlbGxpbmc6IExEQQoKVG8gY2x1c3RlciBhcnRpY2xlcyBpbnRvIHNvbWUgbmF0dXJhbCBncm91cHMgYWNjb3JkaW5nIHRvIHRoZWlyIGNvbnRlbnQgSSB0cmllZCBhIHRvcGljIG1vZGVsaW5nIG1ldGhvZCBjYWxsZWQgTERBIChMYXRlbnQgRGlyaWNobGV0IGFsbG9jYXRpb24pLiBCeSB0aGF0LCB3ZSBjYW4gdHJlYXQgZWFjaCBhcnRpY2xlIGFzIGEgbWl4dHVyZSBvZiB0b3BpY3MuIAoKT24gYSBiYXNpYyBsZXZlbCwgd2UgY2FuIGRvIExEQSBlYXNpbHkgd2l0aCB0aGUgaGVscCBvZiB0aGUg4oCcdG9waWNtb2RlbHPigJ0gcGFja2FnZS4gV2l0aCBqdXN0IGEgZmV3IGxpbmVzIG9mIGNvZGUsIEkgbWFuYWdlZCB0byBkZWZpbmUgMiBkaWZmZXJlbnQgdG9waWNzIHdpdGggdGhlIGZvbGxvd2luZyB0eXBpY2FsIHdvcmRzLiBJdCBpcyBoYXJkIHRvIGRpZmZlcmVudGlhdGUgdGhlIHR3byB0b3BpY3MgKHByb2JhYmx5IGJlY2F1c2UgdGhlIGRhdGEgY29sbGVjdGlvbiBpcyBmaWx0ZXJlZCBvbiBvbmUga2V5d29yZCwgYW5kIHN1YnRvcGljIGFyZSBoaWdobHkgY29ubmVjdGVkIHRvIGVhY2ggb3RoZXIpLCBidXQgd2UgY291bGQgc2F5LCB0aGF0IHRvcGljIDEgaXMgbW9yZSBhYm91dCDigJxob3cgdGhlIEh1bmdhcmlhbiBnb3Zlcm5tZW50IGhhbmRsZXMgY292aWQtMTnigJ0gYW5kIHRvcGljIDIgaXMg4oCcaGVhbHRoY2FyZSBzeXN0ZW0gYW5kIHZhY2NpbmF0aW9u4oCdLiAKCmBgYHtyLCBldmFsPUZ9CmFydF9sZGFfMiA8LSBMREEod29yZF9hbGxfc2l0ZXNfYnlfYXJ0aWNsZV9kdG0sIGsgPSAyLCBjb250cm9sID0gbGlzdChzZWVkID0gMTIzNCkpCmFydF90b3BpY3NfMiA8LSB0aWR5KGFydF9sZGFfMiwgbWF0cml4ID0gImJldGEiKQoKYXJ0X3RvcF90ZXJtc18yIDwtIGFydF90b3BpY3NfMiAlPiUKICBncm91cF9ieSh0b3BpYykgJT4lCiAgdG9wX24oMTAsIGJldGEpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKHRvcGljLCAtYmV0YSkKCmFydF90b3BpY3NfcGxvdF8yIDwtIGFydF90b3BfdGVybXNfMiAlPiUKICBtdXRhdGUodGVybSA9IHJlb3JkZXJfd2l0aGluKHRlcm0sIGJldGEsIHRvcGljKSkgJT4lCiAgZ2dwbG90KGFlcyh0ZXJtLCBiZXRhLCBmaWxsID0gZmFjdG9yKHRvcGljKSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBzY2FsZXMgPSAiZnJlZSIpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3hfcmVvcmRlcmVkKCkKYGBgCgo8Y2VudGVyPiFbXSguLi9wbG90cy9hcnRfdG9waWNzX3Bsb3RfMi5wbmcpe3dpZHRoPTkwJX08L2NlbnRlcj4KCkFsc28gd2l0aCBmZXcgbGluZXMgb2YgY29kZSwgSSBjbHVzdGVyZWQgZWFjaCBhcnRpY2xlIGludG8gb25lIG9mIHRoZSBncm91cHMsIGFuZCBvbiBhIGJveCBwbG90LCB3ZSBjYW4gb2JzZXJ2ZSBob3cgdGhlIGFydGljbGVzIGRpc3RyaWJ1dGVkIGJldHdlZW4gdGhlIHRvcGljcyB3aXRoaW4gZWFjaCBuZXdzIHNpdGUuIEFzIEkgbWVudGlvbmVkIGJlZm9yZSwgdG9waWMgMSBpcyBtb3JlIGFib3V0IHRoZSBIdW5nYXJpYW4gZ292ZXJubWVudCBhbmQgdG9waWMgMiBhYm91dCB0aGUgaGVhbHRoY2FyZSBzeXN0ZW0gYW5kIHZhY2NpbmF0aW9uLiBUaGlzIGFsaWducyB3aXRoIHRoZSBmYWN0LCB0aGF0IGFtb25nIHRoZSBmb3VyIG5ldyBzaXRlcyBpbiB0aGUgcHJvamVjdCBvcmlnby5odSBpcyB0aGUgb25seSBwcm8tZ292ZXJubWVudCBuZXdzIHNpdGUgYXMgdGhlIHBhdHRlcm4gaXMgZGlmZmVyZW50IGNvbXBhcmVkIHRvIHRoZSBvdGhlcnMuCgpgYGB7ciwgZXZhbD1GfQpnYW1tYSA8LSBhcnRfbGRhXzIgJT4lCiAgdGlkeShtYXRyaXggPSAiZ2FtbWEiKQoKdG1wIDwtIGxlZnRfam9pbihnYW1tYSwgYWxsX3NpdGVzLCBieSA9IGMoImRvY3VtZW50IiA9ICJ0aXRsZSIpKQoKcGxvdF8yIDwtIHRtcCAlPiUgCiAgbXV0YXRlKHNpdGUgPSByZW9yZGVyKHNpdGUsIGdhbW1hICogdG9waWMpKSAlPiUKICBnZ3Bsb3QoYWVzKGZhY3Rvcih0b3BpYyksIGdhbW1hKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBmYWNldF93cmFwKH4gc2l0ZSkgKwogIGxhYnMoeCA9ICJUb3BpYyIsCiAgICAgICB5ID0gIiMgb2YgbWVzc2FnZXMgd2hlcmUgdGhpcyB3YXMgdGhlIGhpZ2hlc3QgJSB0b3BpYyIpCmBgYAoKPGNlbnRlcj4hW10oLi4vcGxvdHMvcGxvdF8yLnBuZyl7d2lkdGg9OTAlfTwvY2VudGVyPgoKQXMgd2UgaGF2ZSBmb3VyIG5ld3Mgc2l0ZXMgaXQgc2VlbWVkIHRvIHdvcnRoIHRyeWluZyBmb3VyIGRpZmZlcmVudCB0b3BpY3MuIEkgd291bGQgbGFiZWwgdGhlIGZvbGxvd2luZyB0b3BpY3MgYXMgdGhlIGZvbGxvd2luZyBhY2NvcmRpbmcgdG8gbXkgSHVuZ2FyaWFuIGtub3dsZWRnZS4KCi0gVG9waWMgMTogUGFuZGVtaWMgaGVhbHRoY2FyZSBzeXN0ZW0KLSBUb3BpYyAyOiBWYWNjaW5hdGlvbgotIFRvcGljIDM6IEh1bmdhcmlhbiBnb3Zlcm5tZW50Ci0gVG9waWMgNDogUGFuZGVtaWMgc3RhdHMKCmBgYHtyLCBldmFsPUZ9CmFydF9sZGFfNCA8LSBMREEod29yZF9hbGxfc2l0ZXNfYnlfYXJ0aWNsZV9kdG0sIGsgPSA0LCBjb250cm9sID0gbGlzdChzZWVkID0gMTIzNCkpCmFydF90b3BpY3NfNCA8LSB0aWR5KGFydF9sZGFfNCwgbWF0cml4ID0gImJldGEiKQoKYXJ0X3RvcF90ZXJtc180IDwtIGFydF90b3BpY3NfNCAlPiUKICBncm91cF9ieSh0b3BpYykgJT4lCiAgdG9wX24oMTAsIGJldGEpICU+JQogIHVuZ3JvdXAoKSAlPiUKICBhcnJhbmdlKHRvcGljLCAtYmV0YSkKCmFydF90b3BpY3NfcGxvdF80IDwtIGFydF90b3BfdGVybXNfNCAlPiUKICBtdXRhdGUodGVybSA9IHJlb3JkZXJfd2l0aGluKHRlcm0sIGJldGEsIHRvcGljKSkgJT4lCiAgZ2dwbG90KGFlcyh0ZXJtLCBiZXRhLCBmaWxsID0gZmFjdG9yKHRvcGljKSkpICsKICBnZW9tX2NvbChzaG93LmxlZ2VuZCA9IEZBTFNFKSArCiAgZmFjZXRfd3JhcCh+IHRvcGljLCBzY2FsZXMgPSAiZnJlZSIpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3hfcmVvcmRlcmVkKCkKYGBgCgo8Y2VudGVyPiFbXSguLi9wbG90cy9hcnRfdG9waWNzX3Bsb3RfNC5wbmcpe3dpZHRoPTkwJX08L2NlbnRlcj4KCk9uIHRoZSBmb2xsb3dpbmcgZmFtaWxpYXIgcGxvdCB3ZSBjYW4gc2VlLCB0aGF0IHJlZ2FyZGluZyB0b3BpYyAxLCBtb3N0IG9mIHRoZSBzaXRlcyBhcmUgZG9pbmcgc2ltaWxhci4gQWJvdXQgdG9waWMgMiAodmFjY2luYXRpb24pIG9yaWdvLmh1IGlzIHdyaXRpbmcgbGVzcyB0aGFuIG90aGVycy4gQWxzbywgd2l0aCB0b3BpYyAzLiAoSHVuZ2FyaWFuIEdvdmVybm1lbnQpIHRoZSBvZGQtb25lLW91dCBpcyBzdGlsbCBvcmdpby5odS4gT24gdG9waWMgZm91ciBJIHdvdWxkIG5vdCBoaWdobGlnaHQgYW55IG1lYW5pbmdmdWwgcGF0dGVybi4KCmBgYHtyLCBldmFsPUZ9CmdhbW1hIDwtIGFydF9sZGFfNCAlPiUKICB0aWR5KG1hdHJpeCA9ICJnYW1tYSIpCgp0bXAgPC0gbGVmdF9qb2luKGdhbW1hLCBhbGxfc2l0ZXMsIGJ5ID0gYygiZG9jdW1lbnQiID0gInRpdGxlIikpCgpwbG90XzQgPC0gdG1wICU+JSAKICBtdXRhdGUoc2l0ZSA9IHJlb3JkZXIoc2l0ZSwgZ2FtbWEgKiB0b3BpYykpICU+JQogIGdncGxvdChhZXMoZmFjdG9yKHRvcGljKSwgZ2FtbWEpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGZhY2V0X3dyYXAofiBzaXRlKSArCiAgbGFicyh4ID0gIlRvcGljIiwKICAgICAgIHkgPSAiIyBvZiBtZXNzYWdlcyB3aGVyZSB0aGlzIHdhcyB0aGUgaGlnaGVzdCAlIHRvcGljIikKYGBgCgo8Y2VudGVyPiFbXSguLi9wbG90cy9wbG90XzQucG5nKXt3aWR0aD05MCV9PC9jZW50ZXI+CgojIE5ldHdvcmtzCgpUbyB2aXN1YWxpemUgdGhlIGNvbGxlY3RlZCBiaWdyYW1zIHRoYXQgd2VyZSBkZXNjcmliZWQgaW4gYSBwcmV2aW91cyBjaGFwdGVyIHdlIGNhbiBhbHNvIHVzZSBncmFwaHMgdXNpbmcgdGhlIGdncmFwaCBwYWNrYWdlLiBGaXJzdCwgbGV04oCZcyBzZWUgYSBncmFwaCB3aGVyZSBub2RlcyBhcmUgd29yZHMgYW5kIHRoZXkgYXJlIGNvbm5lY3RlZCB3aXRoIGEgd2VpZ2h0ZWQgZWRnZSBpZiB0aGV5IHdlcmUgdXNlZCB0b2dldGhlciBhIGxvdCBvZiB0aW1lcy4gCgpUbyBoaWdobGlnaHQgc29tZSBkaXN0aW5jdCBncm91cHMsIG9uIHRoZSBsZWZ0IHNpZGUgd2UgY2FuIHNlZSBhIGdyb3VwIHRoYXQgaXMgbW9zdGx5IGFib3V0IGNvdmlkLXN0YXRpc3RpY3MgKG51bWJlciBvZiBpbmZlY3Rpb25zKS4gSW4gdGhlIG1pZGRsZSwgdGhlcmUgaXMgYSBncm91cCB0YWxraW5nIGFib3V0IHRoZSBSdXNzaWFuIGFuZCB0aGUgQ2hpbmVzZSB2YWNjaW5lLgoKYGBge3IsIGV2YWw9Rn0Kc2V0LnNlZWQoMjAyMSkKbmV0d29ya19hbGwgPC0gc3VtbWFyeV9iaWdyYW1zX2FsbF9zaXRlcyAlPiUKICBmaWx0ZXIobiA+PSAzMDApICU+JQogIGdyYXBoX2Zyb21fZGF0YV9mcmFtZSgpICU+JQogIGdncmFwaChsYXlvdXQgPSAiZnIiKSArCiAgZ2VvbV9lZGdlX2xpbmsoYWVzKGVkZ2VfYWxwaGEgPSAwLjYsIGVkZ2Vfd2lkdGggPSBuKSwgZWRnZV9jb2xvdXIgPSAiY3lhbjQiKSArCiAgZ2VvbV9ub2RlX3BvaW50KHNpemUgPSA1KSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgcG9pbnQucGFkZGluZyA9IHVuaXQoMC4yLCAibGluZXMiKSkgKwogIHRoZW1lX3ZvaWQoKQpgYGAKCjxjZW50ZXI+IVtdKC4uL3Bsb3RzL25ldHdvcmtfYWxsLnBuZyl7d2lkdGg9OTAlfTwvY2VudGVyPgoKT24gdGhlIG90aGVyIGhhbmQsIHdpdGggZ3JhcGggdmlzdWFsaXphdGlvbiwgSSB0aGluayB3ZSBjYW4gZG8gYmV0dGVyIHRoYW4ganVzdCBzaG93aW5nIGJpZ3JhbXMuIFdpdGggdGhlIOKAnHdpZHly4oCdIHBhY2thZ2UsIHdlIGNhbiBvYnNlcnZlIGNvbm5lY3Rpb25zIGJldHdlZW4gd29yZHMgdGhhdCBhcHBlYXJlZCBpbiB0aGUgc2FtZSBhcnRpY2xlLiAKCkFnYWluLCB3aXRoIHNvbWUgbGluZXMgb2YgY29kZSBoZXJlIGlzIHRoZSBuZXR3b3JrIG9mIHRoZSBtb3N0IGZyZXF1ZW50bHkgY28tb2NjdXJyZWQgd29yZHMgaW4gYWxsIHRoZSBhcnRpY2xlcyBmcm9tIGFsbCBuZXdzIHNpdGVzLiBXZSBjYW4gc2VlIHRoYXQgdGhlIG1haW4gY2VudGVyIHBvaW50IGFyZSDigJxrb3JvbmF2w61ydXPigJ0gKGNvdmlkLTE5KSwg4oCcdmFrY2luYeKAnSAodmFjY2luZSksIOKAnGrDoXJ2w6FueeKAnSAocGFuZGVtaWMpLCDigJxzesOhbWHigJ0gKG51bWJlciBvZiksIGFuZCB0aGVyZSBhcmUgc29tZSBzZXBhcmF0ZWQgYnV0IGludGVyZXN0aW5nIGdyb3VwcyBsaWtlIOKAnE9yYsOhbiBWaWt0b3LigJ0gYW5kIOKAnG9wZXJhdMOtdiB0w7ZyenPigJ0oSHVuZ2FyaWFuIG9yZ2FuaXphdGlvbiB0aGF0IGlzIGhhbmRsaW5nIHRoZSBwYW5kZW1pYyBzaXR1YXRpb24pLgoKYGBge3IsIGV2YWw9Rn0KdGlkeV9hbGxfc2l0ZXNfYnlfYXJ0aWNsZSA8LSBhbGxfc2l0ZXMgJT4lIAogIHVubmVzdF90b2tlbnMod29yZCwgY29udGVudF9mdWxsKSAlPiUgCiAgZmlsdGVyKCFzdHJfZGV0ZWN0KHdvcmQsICJcXGQrIikpICU+JSAKICBhbnRpX2pvaW4oaHVfc3RvcF93b3JkKSAlPiUgCiAgY291bnQodGl0bGUsIHdvcmQpCgpjb29jdXJyaW5nX3dvcmRzIDwtIHRpZHlfYWxsX3NpdGVzX2J5X2FydGljbGUgJT4lIHBhaXJ3aXNlX2NvdW50KHdvcmQsIHRpdGxlLCBzb3J0ID0gVFJVRSwgdXBwZXIgPSBGQUxTRSkKc2F2ZVJEUyhjb29jdXJyaW5nX3dvcmRzLCBmaWxlID0gJ2RhdGEvcmF3L2Nvb2N1cnJpbmdfd29yZHNfY29udGVudC5yZHMnKQoKCnNldC5zZWVkKDEyMzQpCmNvb2N1cnJpbmdfd29yZHNfY29udGVudF9wbG90IDwtIGNvb2N1cnJpbmdfd29yZHMgJT4lCiAgZmlsdGVyKG4gPj0gMTA1MCkgJT4lCiAgZ3JhcGhfZnJvbV9kYXRhX2ZyYW1lKCkgJT4lCiAgZ2dyYXBoKGxheW91dCA9ICJmciIpICsKICBnZW9tX2VkZ2VfbGluayhhZXMoZWRnZV9hbHBoYSA9IG4sIGVkZ2Vfd2lkdGggPSBuKSwgZWRnZV9jb2xvdXIgPSAiY3lhbjQiKSArCiAgZ2VvbV9ub2RlX3BvaW50KHNpemUgPSA1KSArCiAgZ2VvbV9ub2RlX3RleHQoYWVzKGxhYmVsID0gbmFtZSksIHJlcGVsID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgcG9pbnQucGFkZGluZyA9IHVuaXQoMC4yLCAibGluZXMiKSkgKwogIHRoZW1lX3ZvaWQoKSsKICBnZ3RpdGxlKCJDby1vY2N1cmluZyB3b3JkcyBpbiB0aGUgY29udGVudCBvZiBhcnRpY2xlcyIpCmBgYAoKPGNlbnRlcj4hW10oLi4vcGxvdHMvY29vY3VycmluZ193b3Jkc19jb250ZW50X3Bsb3QucG5nKXt3aWR0aD05MCV9PC9jZW50ZXI+CgpBbHNvLCB3aXRoIHRoZSBzYW1lIGxvZ2ljLCBJIGNyZWF0ZWQgdGhlIG5ldHdvcmsgb2YgdGhlIGNvLW9jY3VycmluZyB3b3JkcyBpbiB0aGUgdGl0bGUgb2YgYXJ0aWNsZXMsIHdoaWNoIHNob3dzIGFuIGV2ZW4gbW9yZSBpbnRlcmVzdGluZyBwYXR0ZXJuLiBJdCBoYXMgdGhyZWUgbWFpbiBncm91cHM6CgotIG9uIHRoZSBsZWZ0IHNpZGU6IHN0YXRzIGFib3V0IGNvdmlkCi0gaW4gdGhlIG1pZGRsZTogcGFuZGVtaWMgZ2VuZXJhbAotIGluIHRoZSBib3R0b206IHZhY2NpbmF0aW9uCgpgYGB7ciwgZXZhbD1GfQojIHdpdGggY29udGVudCBvZiB0aXRsZXMKdGlkeV9hbGxfc2l0ZXNfYnlfdGl0bGUgPC0gYWxsX3NpdGVzICU+JSAKICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRpdGxlLCBkcm9wPUYpICU+JSAKICBmaWx0ZXIoIXN0cl9kZXRlY3Qod29yZCwgIlxcZCsiKSkgJT4lIAogIGFudGlfam9pbihodV9zdG9wX3dvcmQpICU+JSAKICBjb3VudCh0aXRsZSwgd29yZCkKCmNvb2N1cnJpbmdfd29yZHNfdGl0bGUgPC0gdGlkeV9hbGxfc2l0ZXNfYnlfdGl0bGUgJT4lIHBhaXJ3aXNlX2NvdW50KHdvcmQsIHRpdGxlLCBzb3J0ID0gVFJVRSwgdXBwZXIgPSBGQUxTRSkKc2F2ZVJEUyhjb29jdXJyaW5nX3dvcmRzX3RpdGxlLCBmaWxlID0gJ2RhdGEvcmF3L2Nvb2N1cnJpbmdfd29yZHNfdGl0bGUucmRzJykKCnNldC5zZWVkKDEyMzQpCgpjb29jdXJyaW5nX3dvcmRzX2NvbnRlbnRfcGxvdF90aXRsZSA8LSBjb29jdXJyaW5nX3dvcmRzX3RpdGxlICU+JQogIGZpbHRlcihuID49IDE1KSAlPiUKICBncmFwaF9mcm9tX2RhdGFfZnJhbWUoKSAlPiUKICBnZ3JhcGgobGF5b3V0ID0gImZyIikgKwogIGdlb21fZWRnZV9saW5rKGFlcyhlZGdlX2FscGhhID0gbiwgZWRnZV93aWR0aCA9IG4pLCBlZGdlX2NvbG91ciA9ICJjeWFuNCIpICsKICBnZW9tX25vZGVfcG9pbnQoc2l6ZSA9IDUpICsKICBnZW9tX25vZGVfdGV4dChhZXMobGFiZWwgPSBuYW1lKSwgcmVwZWwgPSBUUlVFLCAKICAgICAgICAgICAgICAgICBwb2ludC5wYWRkaW5nID0gdW5pdCgwLjIsICJsaW5lcyIpKSArCiAgdGhlbWVfdm9pZCgpKwogIGdndGl0bGUoIkNvLW9jY3VyaW5nIHdvcmRzIGluIGFsbCBhcnRpY2xlIHRpdGxlcyIpCmBgYAoKPGNlbnRlcj4hW10oLi4vcGxvdHMvY29vY3VycmluZ193b3Jkc19jb250ZW50X3Bsb3RfdGl0bGUucG5nKXt3aWR0aD05MCV9PC9jZW50ZXI+CgpGaW5hbGx5LCBsZXTigJlzIHNlZSB0aGUgY28tb2NjdXJyaW5nIHdvcmRzIGluIHRoZSB0aXRsZXMgc2l0ZSBieSBzaXRlLiBUaGUgaW50ZXJwcmV0YXRpb24gb2YgdGhlbSBpcyBwcmV0dHkgc3RyYWlnaHRmb3J3YXJkIGJ5IHRoZSBuYXR1cmUgb2YgdGhlIGdyYXBoIHZpc3VhbGl6YXRpb24gYW5kIHdlIGNhbiBzYXkgdGhhdCB0aGUgcGF0dGVybnMgYXJlIG1vc3RseSB0aGUgc2FtZSBhdCBhbGwgbmV3cyBzaXRlcy4gCgo8Y2VudGVyPiFbXSguLi9wbG90cy9jb29jdXJyaW5nX3dvcmRzX2NvbnRlbnRfcGxvdF90aXRsZV90ZWxleC5wbmcpe3dpZHRoPTcwJX08L2NlbnRlcj4KCjxjZW50ZXI+IVtdKC4uL3Bsb3RzL2Nvb2N1cnJpbmdfd29yZHNfY29udGVudF9wbG90X3RpdGxlX2luZGV4LnBuZyl7d2lkdGg9NzAlfTwvY2VudGVyPgoKPGNlbnRlcj4hW10oLi4vcGxvdHMvY29vY3VycmluZ193b3Jkc19jb250ZW50X3Bsb3RfdGl0bGVfMjRodS5wbmcpe3dpZHRoPTcwJX08L2NlbnRlcj4KCjxjZW50ZXI+IVtdKC4uL3Bsb3RzL2Nvb2N1cnJpbmdfd29yZHNfY29udGVudF9wbG90X3RpdGxlX29yaWdvLnBuZyl7d2lkdGg9NzAlfTwvY2VudGVyPgoKIyMgQ29uY2x1c2lvbgoKQXMgYSBjb25jbHVzaW9uLCBJIHdvdWxkIGxpa2UgdG8gaGlnaGxpZ2h0IHRoZSBwb3dlciBvZiBSIGFuZCB0aGUgdXNlZCBwYWNrYWdlcyBpbiB0ZXh0IG1pbmluZyBhbmQgYW5hbHlzaXMuIFdpdGggdGhlIGhlbHAgb2Ygc2ltcGxlIHNjcmlwdHMsIGl0IGlzIHBvc3NpYmxlIHRvIGdldCB0aGUgbWFpbiBjb250ZW50IG91dCBmcm9tIHRob3VzYW5kcyBvZiBhcnRpY2xlcyBhbmQgdmlzdWFsaXplIHRoZW0gaW4gYW4gaW50ZXJwcmV0YWJsZSB3YXkuIApBbHNvLCBJIGZlZWwgdGhhdCB0aGlzIHByb2plY3QgY291bGQgYmUgYW4gb25nb2luZyBwcm9qZWN0IGFzIHRoZXJlIGFyZSBlbmRsZXNzIGltcHJvdmVtZW50IHBvc3NpYmlsaXRpZXMgaW4gdGhlIGZvbGxvd2luZyBhcmVhcy4KCi0gU2NyYXBpbmcgb3RoZXIgbmV3cyBzaXRlcwotIE1vcmUgZGF0YSBjbGVhbmluZyBmb3IgYmV0dGVyIHF1YWxpdHkKLSBUcnlpbmcgdG8gdHJhbnNsYXRlIHRvIEVuZ2xpc2ggYW5kIHVzZSBFbmdsaXNoIGRpY3Rpb25hcmllcwotIFVzZSBjb3ZpZCByZWxhdGVkIGRpY3Rpb25hcmllcwotIERlZXBlciB0b3BpYyBtb2RlbGluZwotIERlZXBlciBuZXR3b3JrIGFuYWx5c2lzCgoKCgoKCgoKCgoKCgoKCgoKCgoK